2010-08-05 13 views
7

to jest pierwszy raz, kiedy piszę tutaj, przepraszam, jeśli wiadomość jest nieaktualna lub zbyt długa.Asymetryczne zachowanie dla __getattr__, newstyle vs oldstyle classes

Chciałbym dowiedzieć się więcej o tym, jak ładunki obiektów są pobierane w razie potrzeby. Tak więc przeczytałem dokumentację Pythona 2.7 o nazwie "Model danych" here, poznałem __getattr__ i, w celu sprawdzenia, czy zrozumiałem jego zachowanie, czy nie, napisałem te proste (i niekompletne) owijki tekstowe.

class OldStr: 
    def __init__(self,val): 
    self.field=val 

    def __getattr__(self,name): 
    print "method __getattr__, attribute requested "+name 

class NewStr(object): 
    def __init__(self,val): 
    self.field=val 

    def __getattr__(self,name): 
    print "method __getattr__, attribute requested "+name 

Jak widać są one takie same, z wyjątkiem bycia klasą oldstyle vs newstyle. Ponieważ cytowany tekst mówi, że __getattr__ jest "Wywoływany, gdy wyszukiwanie atrybutów nie odnalazło atrybutu w zwykłych miejscach", chciałem wypróbować operację + na dwóch wystąpieniach tych klas, aby zobaczyć, co się stało, spodziewając się identycznego zachowania.

Ale wyniki mam zastanawiało mnie trochę:

>>> x=OldStr("test") 
>>> x+x 
method __getattr__, attribute requested __coerce__ 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: 'NoneType' object is not callable 

Good! Nie zdefiniowałem metody dla __coerce__ (chociaż oczekiwałem prośby o __add__, nevermind :), więc __getattr__ zaangażowałem się i zwróciłem bezużyteczną rzecz. Ale wtedy

>>> y=NewStr("test") 
>>> y+y 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: unsupported operand type(s) for +: 'NewStr' and 'NewStr' 

Dlaczego ta asymetryczna zachowanie między __getattr__ w Oldstyle klas i jedynek Newstyle przy użyciu wbudowanego operatora jak +? Czy ktoś mógłby mi pomóc zrozumieć, co się dzieje i jaki był mój błąd przy czytaniu dokumentacji?

Bardzo dziękuję, twoja pomoc jest bardzo cenna!

+6

Proszę nie używać klas starego stylu do czegokolwiek. Są przestarzałe z oczywistych powodów - takich jak ten. Ponieważ są przestarzałe, wiedza o tym, jak działają, nie jest pomocna. Odrzuć je i idź dalej, proszę. –

+3

Porównanie zachowania starych i nowych klas pomaga zilustrować działanie klas w nowym stylu, zwłaszcza jeśli znasz klasy w starym stylu. Rzeczywiście nie jest zaskakujące, że działają na różne sposoby, a pocieszające jest, że nowe zajęcia działają zgodnie z oczekiwaniami. Mimo to warto zrozumieć, dlaczego kod jest interpretowany w taki sposób, w jaki jest on niezależny od wersji. –

Odpowiedz

2

Twoje funkcje __getattr__ nie zwracają niczego. Nie wiem, dlaczego klasę starego stylu robi się __getattr__ przed poszukiwaniem __add__, ale tak jest, i to próbuje wywołać wartość zwracaną, która jest None.

Klasa nowego stylu robi to dobrze: nie zdefiniowałeś __add__, więc nie wiesz, jak je dodać.

4

Zobacz Special method lookup for new-style classes.

Metody specjalne są bezpośrednio wyszukiwane w obiekcie klasy, obiekty instancji iw konsekwencji __getattr__() i __getattribute__() są pomijane. Z tego samego powodu nie działa instance.__add__ = foobar.

Służy to przyspieszeniu dostępu do atrybutów. Metody specjalne są nazywane bardzo często, a poddanie ich standardowemu, raczej złożonemu wyszukiwaniu atrybutów znacznie spowolni interpreter.

Wyszukiwanie atrybutów dla klas w starym stylu jest znacznie mniej złożone (w szczególności klasy starego typu nie obsługują deskryptorów), więc nie ma powodu, aby traktować specjalne metody inaczej w klasach starego stylu.