2010-03-08 7 views
152

Ich möchte die __getattr__ Methode für eine Klasse außer Kraft setzen, etwas Phantasie zu tun, aber ich möchte nicht das Standardverhalten zu brechen.Wie überschreibe ich __getattr__ in Python, ohne das Standardverhalten zu brechen?

Was ist der richtige Weg, dies zu tun?

+20

"Pause", fragt es, nicht "ändern". Das ist klar genug: Die "fancy" Attribute sollten nicht mit eingebauten Attributen interferieren und sollten sich so gut wie möglich verhalten. Michaels Antwort ist sowohl korrekt als auch hilfreich. – olooney

Antwort

228

Das Überschreiben __getattr__ sollte in Ordnung sein - __getattr__ wird nur als letztes Mittel aufgerufen, d. H. Wenn in der Instanz keine Attribute vorhanden sind, die mit dem Namen übereinstimmen. Wenn Sie beispielsweise auf foo.bar zugreifen, wird __getattr__ nur aufgerufen, wenn foo kein Attribut mit der Bezeichnung bar hat. Wenn das Attribut ist, das Sie nicht behandeln wollen, heben AttributeError:

class Foo(object): 
    def __getattr__(self, name): 
     if some_predicate(name): 
      # ... 
     else: 
      # Default behaviour 
      raise AttributeError 

Doch im Gegensatz zu __getattr__ wird __getattribute__ zuerst genannt werden (funktioniert nur für neue Stilklassen das heißt jene, die von Objekt erben). In diesem Fall können Sie das Standardverhalten wie so erhalten:

class Foo(object): 
    def __getattribute__(self, name): 
     if some_predicate(name): 
      # ... 
     else: 
      # Default behaviour 
      return object.__getattribute__(self, name) 

the Python docs for more See.

+0

Bah, deine Bearbeitung hat dasselbe, was ich in meiner Antwort gezeigt habe, +1. –

+7

Cool, Python scheint nicht Super-Namen in "__getattr__" zu nennen - irgendwelche Ideen, was zu tun ist? ('AttributError: 'Super' Objekt hat kein Attribut '__getattr __'') – gatoatigrado

+1

Ohne Ihren Code zu sehen, ist es schwer zu sagen, aber das sieht so aus als ob keine Ihrer Superklassen __getattr__ definieren würde. –

26
class A(object): 
    def __init__(self): 
    self.a = 42 

    def __getattr__(self, attr): 
    if attr in ["b", "c"]: 
     return 42 
    raise AttributeError("%r object has no attribute %r" % 
         (self.__class__, attr)) 
    # exception text copied from Python2.6 

>>> a = A() 
>>> a.a 
42 
>>> a.b 
42 
>>> a.missing 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 8, in __getattr__ 
AttributeError: 'A' object has no attribute 'missing' 
>>> hasattr(a, "b") 
True 
>>> hasattr(a, "missing") 
False 
+0

Danke dafür. Ich wollte nur sichergehen, dass ich die Standardnachricht korrekt hatte, ohne in der Quelle herumzukramen. – ShawnFumo

+2

Ich denke, dass 'selbst .__ Klasse __.__ name__' anstelle von' self___ class__' verwendet werden sollte, falls die Klasse '__repr__' überschreibt –

2

Um Michael Antwort zu verlängern, wenn Sie das Standardverhalten mit __getattr__ beibehalten möchten, können Sie es wie so tun:

class Foo(object): 
    def __getattr__(self, name): 
     if name == 'something': 
      return 42 

     # Default behaviour 
     return self.__getattribute__(name) 

Nun ist die Ausnahmemeldung ist kräftigeren :

>>> foo.something 
42 
>>> foo.error 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 5, in __getattr__ 
AttributeError: 'Foo' object has no attribute 'error' 
+1

@ fed.pavlo bist du sicher? Vielleicht hast du '__getattr__' und' _getattribute__' gemischt? –

+0

mein schlechtes. Ich verpasste Anruf zu anderer Methode von Selbst. ( –

Verwandte Themen