Можно установить любое свойство объекта Python - PullRequest
11 голосов
/ 03 мая 2011

Например, этот код Python:

a = object()
a.b = 3

бросков AttributeError: 'object' object has no attribute 'b'

Но этот кусок кода:

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

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

Ответы [ 5 ]

12 голосов
/ 03 мая 2011

Тип 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. Если пользователь вашего класса хочет сохранить некоторые дополнительные атрибуты в экземплярах класса, нет причин не допускать их, и на самом деле есть много причин, по которым вы можете захотеть.

3 голосов
/ 03 мая 2011

Вы можете переопределить поведение магического метода __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

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

2 голосов
/ 03 мая 2011

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

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

0 голосов
/ 03 мая 2011

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

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

>>> a = lambda: None
>>> a.b = 3
>>> a.b 
3
0 голосов
/ 03 мая 2011

Это происходит потому, что когда вы говорите 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.

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