Python: Может ли класс запретить клиентам устанавливать новые атрибуты? - PullRequest
12 голосов
/ 29 июня 2010

Я только что потратил слишком много времени на ошибку, подобную следующей:

>>> class Odp():
    def __init__(self):
        self.foo = "bar"


>>> o = Odp()
>>> o.raw_foo = 3 # oops - meant o.foo

У меня есть класс с атрибутом. Я пытался установить это, и удивлялся, почему это не имело никакого эффекта. Затем я вернулся к исходному определению класса и увидел, что атрибут был назван немного по-другому. Таким образом, я создавал / устанавливал новый атрибут вместо того, который предназначался для.

Во-первых, разве это не тот тип ошибок, который должны предотвращать статически типизированные языки? В этом случае в чем преимущество динамического набора текста?

Во-вторых, есть ли способ, которым я мог бы запретить это при определении Odp и таким образом избавить себя от неприятностей?

1 Ответ

21 голосов
/ 29 июня 2010

Вы можете реализовать метод __setattr__ для этой цели - он гораздо надежнее, чем __slots__, который часто неправильно используется для этой цели (например, __slots__ автоматически «теряется», когда класс наследуется от , в то время как __setattr__ сохраняется, если явно не переопределено).

def __setattr__(self, name, value):
  if hasattr(self, name):
    object.__setattr__(self, name, value)
  else:
    raise TypeError('Cannot set name %r on object of type %s' % (
                    name, self.__class__.__name__))

Вы должны будете убедиться, что hasattr будет успешным для имен, которые do хотите установить, например, путем установки атрибутов на уровне класса или с помощью object.__setattr__ в ваш __init__ метод, а не прямое присвоение атрибута. (Чтобы запретить установку атрибутов для класса , а не для его экземпляров , вам придется определить собственный метакласс с помощью аналогичного специального метода).

...