实例属性在 Python3 中可以是不可变的吗
Can instance attribute be immutable in Python3
我想在 __init__
中设置一个实例属性,然后禁止对其进行任何更改。 Python OOP中有没有这样的机制。更具体地说,我正在使用 Python 3.7.
在您将其否决为重复之前,请注意我说的是 instance attribute
的不变性,而不是 class instance
本身的不变性,就像建议的类似问题标题所询问的那样。
有多种选择,具体取决于您要执行的操作。
1。最终类型
使用 mypy 和 typing_extensions
中的 Final
类型。这仅使用 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。 @属性
使用 属性(可以绕过,但可能不会意外)--
没有setter。您仍然必须将变量存储在某处。可能使用 _
前缀的名称,或者在闭包中,或者直接在带有 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
。
我想在 __init__
中设置一个实例属性,然后禁止对其进行任何更改。 Python OOP中有没有这样的机制。更具体地说,我正在使用 Python 3.7.
在您将其否决为重复之前,请注意我说的是 instance attribute
的不变性,而不是 class instance
本身的不变性,就像建议的类似问题标题所询问的那样。
有多种选择,具体取决于您要执行的操作。
1。最终类型
使用 mypy 和 typing_extensions
中的 Final
类型。这仅使用 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。 @属性
使用 属性(可以绕过,但可能不会意外)--
没有setter。您仍然必须将变量存储在某处。可能使用 _
前缀的名称,或者在闭包中,或者直接在带有 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
。