Может установить любое свойство объекта Python

Например, этот код является Python:

a = object()
a.b = 3

throws AttributeError: 'object' object has no attribute 'b'

Но этот фрагмент кода:

class c(object): pass
a = c()
a.b = 3

просто отлично. Почему я могу назначить свойство b, когда класс x не имеет этого свойства? Как я могу сделать, чтобы мои классы имели только определенные свойства?

Ответ 1

Тип object - это встроенный класс, написанный на C, и не позволяет добавлять к нему атрибуты. Он был явно закодирован, чтобы предотвратить его.

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

class c(object):
    __slots__ = "foo", "bar", "baz"

a = c()

a.foo = 3  # works
a.b   = 3  # AttributeError

Конечно, есть некоторые предостережения с таким подходом: вы не можете рассортировать такие объекты, и код, который ожидает, что каждый объект будет иметь атрибут __dict__. "Более Pythonic" способ будет использовать пользовательский __setattr__(), как показано другим плакатом. Конечно, есть много способов обойти это и никак не устанавливать параметр __slots__ (кроме подкласса и добавления ваших атрибутов в подкласс).

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

Ответ 2

Вы можете переопределить поведение магического метода __setattr__ так.

class C(object):
    def __setattr__(self, name, value):
        allowed_attrs = ('a', 'b', 'c')
        if name not in allowed_attrs:
            # raise exception
            # or do something else
            pass
        self.__dict__[name] = value

Конечно, это только помешает вам установить такие атрибуты, как a.b(точечная форма). Вы можете установить атрибуты с помощью a.__dict__[b]= value. В этом случае вы также должны переопределить метод __dict__.

Ответ 3

Python обычно позволяет вам устанавливать любой атрибут на любой объект. Это особый случай, когда класс object действует по-разному. Существуют также некоторые модули, реализованные в C, которые действуют аналогичным образом.

Если вы хотите, чтобы ваш объект вел себя так, вы можете определить метод __setattr__(self, name, value), который явно выполняет raise AttributeError(), если вы попытаетесь установить член, который не включен в "утвержденный список" (см. http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/389916)

Ответ 4

Создание object экземпляра не имеет никаких функций. Поэтому установка атрибутов в экземпляре базового типа object явно отключена. Вы должны подклассифицировать его, чтобы иметь возможность создавать атрибуты.

Подсказка. Если вы хотите, чтобы простой объект использовался как объект для хранения свойств, вы можете сделать это, создав анонимную функцию с помощью lambda. Функции, являющиеся объектами, также могут хранить атрибуты, поэтому это совершенно правильно:

>>> a = lambda: None
>>> a.b = 3
>>> a.b 
3

Ответ 5

Это происходит потому, что, когда вы говорите a.b = 3, он создает переменную в a, которая представляет b. Например,

class a: pass
print a.b

возвращает AttributeError: class a has no attribute b

Однако этот код,

class a: pass
a.b = 3
print a.b

возвращает 3, поскольку устанавливает значение b в a, в 3.