【问题标题】:Non-mutable list attribute不可变列表属性
【发布时间】:2018-05-14 14:27:15
【问题描述】:

如何创建一个始终包含相同列表的类属性?尽管列表的内容可以更改,但它应该始终引用同一个列表。

显而易见的解决方案是使用属性。

class Table(list):
    def filter(kwargs):
    """Filter code goes here."""


class db:
    _table = Table([1, 2])
    table = property(lambda self: self._table)


db.table.append(3)

我会假设 db.table 应该返回一个列表,并且您应该能够附加到这个列表。但是不行,这段代码会抛出异常:

AttributeError: 'property' object has no attribute 'append'

如何创建始终引用同一个列表的属性?

插图:

db.table = [x for x in db.table if x > 2]
db.filter(3)    # This filter method got lost when reassigning the table in the previous line.

【问题讨论】:

  • class db: table = [1, 2] 有什么问题?
  • db 是一个类,你想要一个实例。
  • 例如你应该做db().table.append(3) 来创建一个实例......
  • 我看不出类属性的类型有多重要。除非您重新分配它,否则它将始终是同一个实例。
  • 您可以在元类中定义属性,如 here 所示,或者 - 这可能是更好的解决方案 - 使 db 成为实例而不是类。

标签: python


【解决方案1】:

这是一个使用类属性的解决方案,使用这个答案:How to make a class property?

class ClassPropertyDescriptor(object):

    def __init__(self, fget, fset=None):
        self.fget = fget
        self.fset = fset

    def __get__(self, obj, klass=None):
        if klass is None:
            klass = type(obj)
        return self.fget.__get__(obj, klass)()

    def __set__(self, obj, value):
        if not self.fset:
            raise AttributeError("can't set attribute")
        type_ = type(obj)
        return self.fset.__get__(obj, type_)(value)

    def setter(self, func):
        if not isinstance(func, (classmethod, staticmethod)):
            func = classmethod(func)
        self.fset = func
        return self

def classproperty(func):
    if not isinstance(func, (classmethod, staticmethod)):
        func = classmethod(func)

    return ClassPropertyDescriptor(func)


class db(object):
        _table = [1,2]

        @classproperty
        def table(cls):
                return list(cls._table)



t = db.table
t.append(3)
print t  # [1, 2, 3]
print db.table  # [1, 2]

【讨论】:

    【解决方案2】:

    没有可以添加的不可变功能。但是,我会提议创建一个存储您的列表的类。并使列表不可变,仅定义设置器并使列表私有。对于列表元素的更改,您可以创建方法。

    你会有类似的东西

    类 FinalList:

    列表

    初始化(列表)

    getList()

    追加(元素)

    删除(元素)

    ...等

    【讨论】:

      【解决方案3】:

      为了比较,这里是编写为类实例的代码。

      class Table(list):
          def filter(kwargs):
              """Filter code goes here."""
      
      
      class DB:
          def __init__(self):
              DB._table = Table([1, 2])
      
          table = property(lambda self: DB._table)
      
      
      db = DB()
      
      db.table.append(3)
      print(db.table)
      db.table = [2]
      

      输出:

      [1, 2, 3]
      AttributeError: can't set attribute
      

      完美。这比创建类属性要简单得多。

      从技术上讲,我们使用了一个类实例,这使得代码变得非常简单。但是,通过将表存储在类本身中,我们确保所有实例共享相同的表。

      【讨论】:

        猜你喜欢
        • 2013-10-30
        • 1970-01-01
        • 1970-01-01
        • 2012-06-25
        • 2020-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多