2011-06-20 6 views
6

Mam słownik taki jak klasa, którego używam do przechowywania niektórych wartości jako atrybutów. Ostatnio dodałem trochę logiki (__getattr__), aby zwrócić Brak, jeśli atrybut nie istnieje. Jak tylko to zrobiłem, marynata rozbił się i chciałem się dowiedzieć, dlaczego?Awaria Pythona podczas próby przywrócenia wartości domyślnej w __getattr__

Code Test:

import cPickle 
class DictionaryLike(object): 
    def __init__(self, **kwargs): 
     self.__dict__.update(kwargs) 

    def __iter__(self): 
     return iter(self.__dict__) 

    def __getitem__(self, key): 
     if(self.__dict__.has_key(key)): 
      return self.__dict__[key] 
     else: 
      return None 

    ''' This is the culprit...'''  
    def __getattr__(self, key): 
     print 'Retreiving Value ' , key 
     return self.__getitem__(key) 

class SomeClass(object): 
    def __init__(self, kwargs={}): 
     self.args = DictionaryLike(**kwargs) 


someClass = SomeClass() 
content = cPickle.dumps(someClass,-1) 
print content 

Wynik:

Retreiving Value __getnewargs__ 
Traceback (most recent call last): 
    File <<file>> line 29, in <module> 
    content = cPickle.dumps(someClass,-1) 
TypeError: 'NoneType' object is not callable` 

zrobiłem coś głupiego? Czytałem posta, że ​​deepcopy() może wymagać, aby rzucić wyjątek, jeśli klucz nie istnieje? Jeśli tak, to czy istnieje łatwy sposób osiągnięcia tego, co chcę, bez rzucania wyjątku?

Wynik końcowy jest, że jeśli niektóre połączenia

someClass.args.i_dont_exist 

chcę go zwrócić None.

Odpowiedz

13

Implementacja __getattr__ jest nieco skomplikowana, ponieważ jest wywoływana dla każdego nieistniejącego atrybutu. W twoim przypadku moduł pickle testuje twoją klasę dla specjalnej metody __getnewargs__ i odbiera None, co oczywiście nie jest możliwe do wywołania.

może chcesz zmienić __getattr__ zadzwonić realizację podstawy do magicznych nazwach:

def __getattr__(self, key): 
    if key.startswith('__') and key.endswith('__'): 
     return super(DictionaryLike, self).__getattr__(key) 
    return self.__getitem__(key) 

zazwyczaj przechodzą przez wszystkich nazw rozpoczynających się od znaku podkreślenia, tak, że można ominąć magię dla symboli wewnętrznych.

+0

Myślę, że to może być najlepsze dla mojej sprawy, ponieważ _ i \ _ \ _ nigdy nie będą nazwami atrybutów. – Nix

+0

To jest naprawdę sprytne Nigdy nie myślałem, że to zrobię – GWW

+0

dude, że tak bardzo mnie tu uratowałeś – Greg

5

Trzeba podnieść AttributeError gdy atrybut nie jest obecny w swojej klasie:

def __getattr__(self, key): 
    i = self.__getitem__(key) 
    if i == None: 
     raise AttributeError 
    return self.__getitem__(key) 

mam zamiar założyć, że takie zachowanie jest wymagane. Z dokumentacji Pythona dla getattr, "Wywoływane, gdy wyszukiwanie atrybutów nie odnalazło atrybutu w zwykłych miejscach (tj. Nie jest to atrybut instancji ani nie jest znalezione w drzewie klas dla siebie) .na to nazwa atrybutu. powinien zwrócić (obliczyć) wartość atrybutu lub podnieść wyjątek AttributeError. "

Nie ma sposobu, aby powiedzieć pikle itp., Że szukany atrybut nie zostanie znaleziony, chyba że zgłosisz wyjątek. Na przykład, w twoim komunikacie o błędzie pickle szuka specjalnej metody wywoływanej o nazwie __getnewargs__, pickle oczekuje, że jeśli nie zostanie znaleziony wyjątek AttributeError, zwracana wartość będzie wywoływalna.

Sądzę, że potencjalna praca wokół ciebie może być może spróbuj zdefiniować wszystkie metody specjalne, które pickle szuka jako manekinowe metody?

+0

Czy istnieje sposób na obejście tego problemu (czy widziałaś moją ostatnią zmianę)? – Nix

+0

@Następka: Oh, nie widziałem twojego ostatniego komentarza. – GWW

+0

Może nie być możliwe uzyskanie tego, co chcę ... Chciałem tylko obejść konieczność sprawdzenia hasattr za każdym razem. – Nix

Powiązane problemy