2011-08-12 17 views
29

Chcę zastąpić moje metody klasy Python __getattribute__ i __setattr__. Mój przypadek użycia jest zwykle jeden: Mam kilka specjalnych nazw, które chcę obsługiwać, i chcę domyślne zachowanie dla czegokolwiek innego. W przypadku __getattribute__ wydaje się, że mogę zażądać domyślnego zachowania po prostu podnosząc AttributeError. Jak jednak osiągnąć to samo w __setattr__? Oto banalny przykład, implementujący klasę z niezmiennymi polami "A", "B" i "C".Jak poprawnie zastąpić __setattr__ i __getattribute__ dla klas w nowym stylu w Pythonie?

class ABCImmutable(SomeSuperclass): 
    def __getattribute__(self, name): 
     if name in ("A", "B", "C"): 
      return "Immutable value of %s" % name 
     else: 
      # This should trigger the default behavior for any other 
      # attribute name. 
      raise AttributeError() 

    def __setattr__(self, name, value): 
     if name in ("A", "B", "C"): 
      raise AttributeError("%s is an immutable attribute.") 
     else: 
      # How do I request the default behavior? 
      ??? 

Co jest na miejscu ze znakami zapytania? W przypadku klas w starym stylu odpowiedź brzmiała: self.__dict__[name] = value, ale dokumentacja wskazuje, że jest to niewłaściwe w przypadku klas w nowym stylu.

+0

"dokumentacja wskazuje, że jest to niewłaściwe w przypadku zajęć w nowym stylu" ... i czy nie wskazano, co jest właściwe w przypadku zajęć w nowym stylu? – Gerrat

+0

Dlaczego po prostu nie implementujesz nazwanych pól jako właściwości tylko do ustawienia? – katrielalex

+2

Niezmienność była po prostu trywialnym przykładem użycia __setattr__. Moje faktyczne użycie jest nieco bardziej skomplikowane. Moja klasa dziedziczy po Dict, ale dodatkowo niektóre specjalne klucze (określone w czasie wykonywania) są dostępne jako "object.key" zamiast "object ['key']". Prawdopodobnie mógłbym dodać je jako właściwości za pomocą środowiska wykonawczego lub coś podobnego, ale łatwiej używać "__getattr__" i "__setattr__", a wydajność nie jest szczególnie krytyczna. –

Odpowiedz

28

To

super(ABCImmutable, self).__setattr__(name, value) 

w Pythonie 2, lub

super().__setattr__(name, value) 

w Pythonie 3.

Również podniesienie AttributeError jest nie jak spadasz z powrotem do domyślnego zachowania dla __getattribute__ . Spadasz z powrotem do domyślnego z

return super(ABCImmutable, self).__getattribute__(name) 

w Pythonie 2 lub

return super().__getattribute__(name) 

w Pythonie 3.

Podnoszenie AttributeError pomija domyślną obsługę i idzie do __getattr__, lub po prostu produkuje AttributeError w kod wywołujący, jeśli nie ma __getattr__.

Zobacz dokumentację na stronie Customizing Attribute Access.

+3

Zamknij, ale nie potrzebujesz drugiego "self". Nazwałbyś to tak: super (ABCImmutable, self) .__ setattr __ (name, value) W przeciwnym razie otrzymasz "oczekiwane 2 argumenty, ale dostałem trzy" wyjątek. – Dave

5

SomeSuperclass.__setattr__(self, name, value)?

+0

Czy nie muszę gdzieś dzwonić do 'super'? Przynajmniej w ogólnym przypadku? –

+0

@Ryan Thompson Jestem prawie pewien, że możesz użyć 'super()' zamiast 'SomeSuperclass' ale próbuję wyśledzić czy to jest specyficzne dla Pythona 3. –

+0

@Ryan Thompson Patrząc na [Python 2 przykładów dla Raymonda Hettingera "Python's super() za super!" post] (http://code.activestate.com/recipes/577721-how-to-use-super-effectively-python-27-version/), wygląda na to, że byłoby to super (ABCImmutable, self) .__ setattr__ (self, name, value) 'w Pythonie 2. Zaktualizuję moją odpowiedź z tym, co moim zdaniem powinno być poprawnym wywołaniem. –