2009-07-02 14 views
17

W Pythonie jest nielegalne, aby utworzyć nowy atrybut dla instancji obiektów jak tenPython Język Pytanie: atrybuty obiektu() vs Funkcja

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

rzuca

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

Jednak dla funkcji obiekt, jest OK.

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

Jakie jest uzasadnienie tej różnicy?

+0

+1, właśnie o zadać dokładnie to samo pytanie, ale potem przypomniałem sobie, aby najpierw wyszukać istniejący! Dobre odpowiedzi również poniżej. – Edmund

+0

bardzo dobre pytanie, mam podobny problem –

+0

możliwy duplikat [Nie można ustawić atrybutów klasy obiektu] (http://stackoverflow.com/questions/1529002/cant-set-attributes-of-object-class) –

Odpowiedz

22

Obiekty funkcji przyczyny obsługują atrybuty arbitralne to to, że zanim dodaliśmy tę funkcję, kilka frameworków (np. Generatory parserów) nadużywało funkcji docstrukcji (i innych atrybutów obiektów funkcji), aby ukryć informacje o funkcjach, które były kluczowe dla nich - dość oczywiste było zapotrzebowanie na takie powiązanie arbitralnie nazwanych atrybutów z obiektami funkcyjnymi sprawdzanymi za pomocą przykładów, wspieranie ich bezpośrednio w języku, a nie puntowanie i puszczanie (np.) docstrukcji.

Aby wesprzeć dowolną instancję atrybuty typu musi dostarczyć każdy z jego wystąpień z __dict__ - to nic wielkiego dla funkcji (która nigdy nie są małe obiekty w każdym razie), ale może to być również na innych obiektach przeznaczonych do być malutkie. Dzięki temu, że typ object był tak lekki, jak tylko mogliśmy, a także dostarczaliśmy __slots__, aby umożliwić unikanie instancji __dict__ w podtypach object, obsługiwaliśmy małe, wyspecjalizowane typy "wartości", najlepiej jak potrafimy.

+1

Dzięki Alex, za ten wewnętrzny widok * obiektu *. Mam nadzieję, że zysk w kosmosie był wart wysiłku. Nadal uważam za sprzeczne intuicyjnie, że (a) klasa bazowa systemu obiektowego nie obsługuje jednej z podstawowych cech OO - atrybutów instancji; i (b) ta funkcja nagle powstaje z dowolną niesensyczną pochodną klasy * klasy Foo (obiekt): pass *, której używam częściej niż po prostu dla uzyskania atrybutów instancji. – ThomasH

+2

@Thomas, jesteś równie zaskoczony, że Object w Javie "nie obsługuje jednej z podstawowych funkcji OO" w dokładnie taki sam sposób? Jego bezpośrednie instancje również nie mają atrybutów instancji. Wygląda na to, że C# jest taki sam. Ponieważ (i to jest NAPRAWDĘ podstawową cechą OO: Zasada Liskova!) Żadna podklasa nie może odebrać czegoś, co znajduje się w superklasie, aby zaspokoić twoją intuicję kosztowałaby nieskończoną pamięć: dyktant powinien wtedy mieć __dict ___ ... i TO dyktować powinien oczywiście mieć swój WŁASNY __dysk __... i NIGDY NIGDY nie może przestać. Twoja intuicja wprowadza cię w błąd * DUŻO *! -) –

+1

@Alex Ok, słyszę cię. Ale może to wszystko byłoby możliwe, gdyby \ _ \ _ dict \ _ \ _ obiektów Lean było leniwych ?! Właściwie mogłem sobie wyobrazić, że chcę nanieść adnotację \ _ \ _ dyktować \ _ \ _ z \ _ \ _ dict \ _ \ _ instancji * object * z niewielkim atrybutem i byłoby to dla mnie wystarczające, jeśli to \ _ \ _dict \ _ \ _ powstanie tylko wtedy, gdy po raz pierwszy do niego przypisam. W jaki sposób? – ThomasH

7

Alex Martelli opublikował wspaniałą odpowiedź na twoje pytanie. Dla każdego, kto szuka dobrej drodze do osiągnięcia arbitralnych atrybutów na pustym obiekcie, to zrobić:

class myobject(object): 
    pass 

o = myobject() 
o.anything = 123 

lub bardziej wydajne (i lepiej udokumentowane), jeśli znasz atrybuty:

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

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

Czy jesteś pewien, że pierwszy sposób działa? Próbowałem tego i nie sądzę, że to działa. –

1

Uzasadnieniem jest to, że instancja object() jest zdegenerowanym przypadkiem specjalnym. To "jest" przedmiotem, ale nie jest zaprojektowane, aby było użyteczne samo przez się.

Pomyśl o object jako tymczasowym hackowaniu, łączeniu starych typów i klas. W Pythonie 3.0 będzie zanikać w zapomnienie, ponieważ nie będzie już być stosowane jako część

class Foo(object): 
    pass 

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

Główne rzeczywiste użycie obiektu znajduje się w idiomie 'sentinel = object()'. BYŁA skromnie przydatna do zbudowania "obiektu z niezliczoną ilością", zamiast tworzyć nowe klasy do tego celu, więc razy ;-). –

+0

objectwithadict - zasadniczo "class ObjectWithADict (object): pass'? –

0

Oto kolejna alternatywa, tak krótki, jak mogę zrobić to:

>>> dummy = type('',(), {})() 
>>> dummy.foo = 5 
>>> dummy.foo 
5