Есть несколько вариантов в зависимости от того, что именно вы пытаетесь сделать.
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
все еще являются экспериментальными и могут измениться. Сам Гвидо работал над mypy, поэтому он может даже оказаться в модуле стандартной библиотеки typing
.
2. @ Недвижимости
Используйте свойство (которое можно обойти, но, возможно, не случайно) -
Без сеттера. Вы все еще должны хранить переменную где-то. Может быть, с именем _
с префиксом, или в закрытии, или непосредственно в экземпляре dict с vars
(который пропустит функцию дескриптора из @property
).
class Spam:
def __init__(self, foo):
vars(self)['foo'] = foo
@property
def foo(self):
return vars(self)['foo']
Или с помощью установщика, который проверяет, установлен ли он уже, и вызывает исключение, если это так. Это позволяет вам установить его в первый раз с обычным синтаксисом, но, вероятно, не стоит беспокоиться, если вы установите его в __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
.