2009-07-02 3 views
17

В питоне, это незаконно, чтобы создать новый атрибут для экземпляра объекта, как этогоPython Язык Вопрос: атрибуты объекта() против функции

>>> a = object() 
>>> a.hhh = 1 

бросает

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'object' object has no attribute 'hhh' 

Однако для функции объект, все в порядке.

>>> def f(): 
... return 1 
... 
>>> f.hhh = 1 

В чем причина этой разницы?

+0

+1, я просто о задать один и тот же вопрос, но потом вспомнить, что нужно сначала искать существующий! Хорошие ответы ниже. – Edmund

+0

очень хороший вопрос, у меня есть аналогичная проблема –

+0

Возможный дубликат [Невозможно установить атрибуты класса объектов] (http://stackoverflow.com/questions/1529002/cant-set-attributes-of-object-class) –

ответ

22

Объекты функции причины поддерживают произвольные атрибуты, так это то, что до того, как мы добавили эту функцию, несколько фреймворков (например, генераторы синтаксического анализатора) злоупотребляли функциями docstrings (и другим атрибутом объектов функций), чтобы скрыть информацию о каждой функции, которая была критической для них - необходимость такой ассоциации произвольных именованных атрибутов для функционирования объектов, доказанных на примере, поддерживая их непосредственно на языке, а не отбрасывать и отпускать (например) докстры, злоупотребляемые, была довольно очевидной.

Для поддержки произвольного экземпляра атрибутов типа должен поставить каждый из его экземпляров с __dict__ - это не большим дела для функций (которые никогда не являются крошечными объектами, так или иначе), но это может также быть для других объектов предназначенных для быть крошечным. Сделав модель object такой легкой, как мы могли, а также предоставив __slots__, чтобы избежать исключения в каждом случае __dict__ в подтипах object, мы поддерживали небольшие специализированные «значения», насколько это возможно.

+1

Спасибо, Алекс, за этот внутренний вид * объекта *. Я надеюсь, что выигрыш в космосе стоит того. Я все еще считаю контринтуитивным, что (а) базовый класс объектной системы не поддерживает одну из основных особенностей атрибутов OO - экземпляра; и (б) эта особенность внезапно возникла с любым нечувствительным производным классом * class Foo (object): pass *, который я нахожу себе более чем часто, чтобы получить атрибуты экземпляра. – ThomasH

+2

@Thomas, вы одинаково удивлены тем, что Object в Java «не поддерживает одну из основных функций OO» точно так же? Его прямые экземпляры также не имеют атрибутов экземпляра. Я считаю, что C# - то же самое. Поскольку (и это ДЕЙСТВИТЕЛЬНО основная особенность OO: принцип Лискова!), Ни один подкласс не может отнять что-то, что находится в суперклассе, чтобы удовлетворить вашу интуицию, фактически стоило бы бесконечной памяти: у дикта должна быть __dict ___... и THAT dict должен, конечно, иметь свой СОБСТВЕННЫЙ __dict __... и он НИКОГДА НИКОГДА не останавливается. Ваша интуиция вводит вас в заблуждение * A LOT *! -) –

+1

@Alex Хорошо, я вас слышу. Но, возможно, все это было бы возможно, если бы лёгкие объекты \ _ \ _ dict \ _ \ _ были ленивыми ?! Я действительно мог представить себе, что хочу комментировать файл \ _ \ _ dict \ _ \ _ of \ _ \ _ dict \ _ \ _ экземпляра * object * с небольшим атрибутом, и для меня это было бы вполне достаточно, если бы этот \ _ \ _dict \ _ \ _ будет возникать только тогда, когда я сначала назначу ему. Как так? – ThomasH

7

Алекс Мартелли опубликовал потрясающий ответ на ваш вопрос. Для тех, кто ищет хороший способ, чтобы выполнить произвольные атрибуты на пустой объект, сделайте следующее:

class myobject(object): 
    pass 

o = myobject() 
o.anything = 123 

Или более эффективным (и лучше документированы), если вы знаете, атрибуты:

class myobject(object): 
    __slots__ = ('anything', 'anythingelse') 

o = myobject() 
o.anything = 123 
o.anythingelse = 456 
+0

Вы уверены, что первый способ работает? Я пробовал это, и я не думаю, что это работает. –

1

Обоснование заключается в том, что экземпляр object() является вырожденным частным случаем. Это «объект», но он не предназначен для того, чтобы быть полезным сам по себе.

Подумайте о object как временном взломе, мостах и ​​типах старого стиля. В Python 3.0 это будет исчезать в неизвестности, потому что он больше не будет использоваться как часть

class Foo(object): 
    pass 

f = Foo() 
f.randomAttribute = 3.1415926 
+0

Основное использование объекта в idiom 'sentinel = object()'. Было бы неплохо иметь встроенный «объект», а не создавать новые классы для этой цели, иногда ;-). –

+0

objectwithadict - по существу 'class ObjectWithADict (объект): pass'? –

0

Вот еще одна альтернатива, короче, как я мог бы сделать это:

>>> dummy = type('',(), {})() 
>>> dummy.foo = 5 
>>> dummy.foo 
5 
Смежные вопросы