2009-12-22 13 views
28

wiem, kod ten ma rację:Jaki jest związek między __getattr__ a getattr?

class A: 
    def __init__(self): 
     self.a = 'a' 
    def method(self): 
     print "method print" 

a = A() 
print getattr(a, 'a', 'default') 
print getattr(a, 'b', 'default') 
print getattr(a, 'method', 'default') 
getattr(a, 'method', 'default')() 


I to jest złe:

# will __getattr__ affect the getattr? 

class a(object): 
    def __getattr__(self,name): 
     return 'xxx' 

print getattr(a) 

Jest to również źle:

a={'aa':'aaaa'} 
print getattr(a,'aa') 


Gdzie powinniśmy korzystać z tych funkcji (__getattr__ i getattr)?

+0

możliwy duplikat [Zrozumienie różnicy między \ _ \ _ getattr \ _ \ _ i \ _ \ _ getattribute \ _ \ _] (http://stackoverflow.com/questions/4295678/understanding-the-difference-between- getattr-and-getattribute) – Trilarion

+1

@Trilarion, który nie jest prawidłowym duplikatem tego pytania –

Odpowiedz

47

Alexa odpowiedź była dobra, ale zapewnienie Państwu przykładowy kod skoro pytasz o to :)

class foo: 
    def __init__(self): 
     self.a = "a" 
    def __getattr__(self, attribute): 
     return "You asked for %s, but I'm giving you default" % attribute 


>>> bar = foo() 
>>> bar.a 
'a' 
>>> bar.b 
"You asked for b, but I'm giving you default" 
>>> getattr(bar, "a") 
'a' 
>>> getattr(bar, "b") 
"You asked for b, but I'm giving you default" 

Tak w skrócie odpowiedź jest

użyć

__getattr__ do określić jak obsługiwać atrybuty, które są nie znaleziono

i

getattr do dostaćatrybuty

+3

Uważaj, jeśli używasz '__getattr__', ponieważ łamie on' copy' wbudowany moduł, chyba że zaimplementujesz również '__copy__' i' __deepcopy__' dla swojej klasy. Zajęło mi trochę czasu na prześledzenie tego błędu ... Na 2.7 tak czy inaczej –

33

getattr jest wbudowaną funkcją pobierającą (przynajmniej) dwa argumenty: obiekt, z którego uzyskujesz atrybut, oraz nazwę ciągu atrybutu.

Jeśli nazwa ciąg jest stały, powiedzmy 'foo', getattr(obj, 'foo') jest dokładnie to samo jak obj.foo.

Głównym powodem użycia wbudowanej funkcji getattr jest brak nazwy atrybutu jako stałej, ale raczej jako zmiennej. Drugim ważnym przypadkiem użycia jest przekazanie trzy argumentów, a nie tylko dwa: w takim przypadku, jeśli atrybut nie występuje w obiekcie, getattr zwraca trzeci, "domyślny", argument zamiast podnosić wyjątek.

__getattr__ jest specjalny sposób, zdefiniowane w klasie, która zostanie wywołana, gdy niektóre cechą na przykład tej klasy jest wymagane, i inne zwykłe sposoby dostarczają tego atrybutu (poprzez instancji __dict__ szczeliny, właściwości, a więc on) wszystko nie powiodło się. Możesz go zdefiniować, na przykład, kiedy chcesz przekazać inne, niezdefiniowane odnośniki do innych obiektów.

Twój drugi przykład jest nieprawidłowy, ponieważ wbudowane getattr można nigdy nie być wywoływane z jednym argumentem.

Trzeci nie powiedzie się, ponieważ słownik, z którego próbujesz "uzyskać atrybut", nie ma tego atrybutu - ma pozycji, które są całkowicie rozłączne z atrybutów oczywiście.

+2

Podczas gdy twoja odpowiedź jest doskonała, @ zjm1126 chciał próbki kodu, ponieważ jego angielski nie jest tak dobry. – Kimvais

14

__getattr__() jest specjalną funkcją metody, które można zdefiniować. Gdy wyszukiwanie elementu nie powiedzie się, funkcja ta zostanie wywołana.

getattr() to funkcja, którą można wywołać, aby spróbować wyszukać członka. Jeśli wyszukiwanie się powiedzie, otrzymasz element członkowski (być może obiekt funkcji metody lub obiekt atrybutu danych). getattr() może również zwrócić wartość domyślną w przypadku niepowodzenia wyszukiwania.

Jeśli zadeklarujesz funkcję członka w postaci __getattr__(), możesz czasem ją odnieść, lub możesz ją osiągnąć za każdym razem.

class A(object): 
    def __getattr__(self, name): 
     return "I pretend I have an attribute called '%s'" % name 

a = A() 

print a.foo # prints "I pretend I have an attribute called 'foo'" 

Python posiada również __getattribute__() który zawsze wezwał każdego odnośnika. Jest to bardzo niebezpieczne, ponieważ może uniemożliwić normalny dostęp do członków.

class A(object): 
    def __init__(self, value): 
     self.v = value 
    def __getattribute__(self, name): 
     return "I pretend I have an attribute called '%s'" % name 

a = A(42) 

print a.v # prints "I pretend I have an attribute called 'v'" 
print a.__dict__["v"] # prints "I pretend I have an attribute called '__dict__'" 

Ups, dostęp do a.v jest teraz niemożliwy!

+1

+1 za wzmiankę o __getattribute__, o którym, jak sądzę, chodziło właśnie o to pytanie. – kibitzer

+0

Ładne i proste wyjaśnienie __getattribute__, które zawsze wydawało mi się niejasne. –

Powiązane problemy