Может ли атрибут экземпляра быть неизменным в Python3 - PullRequest
0 голосов
/ 14 января 2019

Я хотел бы установить атрибут экземпляра в __init__ и затем запретить любые изменения в нем. Есть ли такой механизм в ООП Python. В частности, я использую Python 3.7.

Перед тем, как вы проголосуете за него как за дубликат, обратите внимание, что я говорю об неизменности instance attribute вместо неизменности самих class instance, как предлагались аналогичные названия вопросов, о которых спрашивали.

1 Ответ

0 голосов
/ 14 января 2019

Есть несколько вариантов в зависимости от того, что именно вы пытаетесь сделать.

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...