实例属性在Python3中可以不可变吗

时间:2019-01-14 01:30:15

标签: python-3.x immutability

我想在__init__中设置一个实例属性,然后禁止对其进行任何更改。 Python OOP中是否有这样的机制?更具体地说,我正在使用Python 3.7。

在您否决它作为重复项之前,请注意,我所谈论的是instance attribute的不变性,而不是class instance本身的不变性,就像建议的类似问题标题所问的那样。

1 个答案:

答案 0 :(得分:1)

有多种选择,具体取决于您要执行的操作。

1。最终类型

使用mypy和Final中的typing_extensions类型。仅使用mypy进行静态检查,而不是在运行时强制执行。

$ pip install typing_extensions

from typing_extensions import Final

class Spam:
    foo: Final[int]
    def __init__(self, foo):
        self.foo = foo

这在撰写本文时应该可以使用,但是typing_extensions仍处于试验阶段,并且可能会发生变化。 Guido本人一直在研究mypy,因此它甚至可能最终出现在标准库typing模块中。

2。 @property

也使用属性(可以绕开,但可能并非偶然)-

没有二传手。您仍然必须将变量存储在某个地方。也许使用_前缀的名称,或者在闭包中,或者直接在实例字典上使用vars(这将绕过@property的描述符函数)。

class Spam:
    def __init__(self, foo):
        vars(self)['foo'] = foo
    @property
    def foo(self):
        return vars(self)['foo']

或使用setter来检查它是否已设置,并引发异常。这样一来,您就可以使用常规语法进行首次设置,但是如果您在__init__中进行设置,则可能不值得花时间。

3。子类元组

继承自tuple。您必须使用__new__而不是__init__。您获得了真正的不变性,但是这些本身不再是属性,您必须使用整数下标(self[0]等)来访问它们。从tuple继承意味着您也可以获取所有元组方法,而这可能是您不想要的。

如果您仍然希望访问点,则可以尝试创建collections.namedtuple并从中继承。

from collections import namedtuple

class Spam(namedtuple('Spam', 'foo')):
    def __new__(cls, foo):
        return super().__new__(cls, foo)
    def print_foo(self):
        print(self.foo)

当然,您可以通过这种方式继承更多的方法。

另请参见typing.NamedTuple