防止在 __init__ 之外创建新属性

新手上路,请多包涵

我希望能够创建一个类(在 Python 中),该类一旦用 __init__ 初始化,不接受新属性,但接受对现有属性的修改。我可以看到几种 hack-ish 方法来做到这一点,例如有一个 __setattr__ 方法,例如

def __setattr__(self, attribute, value):
    if not attribute in self.__dict__:
        print "Cannot set %s" % attribute
    else:
        self.__dict__[attribute] = value

然后直接在 __init__ 中编辑 __dict__ --- ,但我想知道是否有“正确”的方法来做到这一点?

原文由 astrofrog 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
2 个回答

我不会直接使用 __dict__ ,但是你可以添加一个函数来明确地“冻结”一个实例:

 class FrozenClass(object):
    __isfrozen = False
    def __setattr__(self, key, value):
        if self.__isfrozen and not hasattr(self, key):
            raise TypeError( "%r is a frozen class" % self )
        object.__setattr__(self, key, value)

    def _freeze(self):
        self.__isfrozen = True

class Test(FrozenClass):
    def __init__(self):
        self.x = 42#
        self.y = 2**3

        self._freeze() # no new attributes after this point.

a,b = Test(), Test()
a.x = 10
b.z = 10 # fails

原文由 Jochen Ritzel 发布,翻译遵循 CC BY-SA 2.5 许可协议

插槽是要走的路:

pythonic 方法是使用插槽而不是玩弄 __setter__ 。虽然它可以解决问题,但不会带来任何性能提升。对象的属性存储在字典“ __dict__ ”中,这就是为什么你可以动态地向我们目前创建的类的对象添加属性的原因。使用字典存储属性非常方便,但对于只有少量实例变量的对象来说,这意味着空间浪费。

是解决这个空间消耗问题的好方法。插槽提供了一个静态结构,禁止在创建实例后添加属性,而不是使用允许动态地向对象添加属性的动态字典。

我们在设计类的时候,可以使用槽来防止属性的动态创建。要定义插槽,您必须定义一个名为 __slots__ 的列表。该列表必须包含您要使用的所有属性。我们在下面的类中演示了这一点,其中槽列表仅包含属性“val”的名称。

 class S(object):

    __slots__ = ['val']

    def __init__(self, v):
        self.val = v

x = S(42)
print(x.val)

x.new = "not possible"

=> 它无法创建属性“新”:

 42
Traceback (most recent call last):
  File "slots_ex.py", line 12, in <module>
    x.new = "not possible"
AttributeError: 'S' object has no attribute 'new'

笔记:

  1. 自 Python 3.3 以来,优化空间消耗的优势不再那么令人印象深刻。在 Python 3.3 中, 密钥共享 字典用于对象的存储。实例的属性能够在彼此之间共享其内部存储的一部分,即存储密钥及其对应散列的部分。这有助于减少程序的内存消耗,这些程序会创建许多非内置类型的实例。但仍然是避免动态创建属性的方法。

  2. 使用插槽也需要自己付费。它会破坏序列化(例如 pickle)。它还会破坏多重继承。一个类不能继承自多个定义槽或具有用 C 代码定义的实例布局(如列表、元组或整数)的类。

原文由 Dhia 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题