2016-08-19 5 views
0

Ich lese ein wenig auf Python-Objekt-Attribut-Lookup (hier: https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/#object-attribute-lookup).Python 3 __getattribute__ vs dot Zugriffsverhalten

scheint ziemlich geradlinig, so dass ich es ausprobiert (python3):

class A: 
    def __getattr__(self, attr): 
     return (1,2,3) 

a = A() 

a.foobar #returns (1,2,3) as expected 
a.__getattribute__('foobar') # raises AttributeError 

ist meine Frage nicht die beiden identisch Dibe soll?

Warum löst der zweite einen Attributfehler aus?

So ist die Antwort offensichtlich, dass die Logik für a.foobar unterscheidet sich von der Logik für a.__getattribute("foobar"). Nach den data model: a.foobara.__getattribute("foobar") nennt, und wenn es ein Attribut wirft, nennt es a.-__getattr__('foobar')

So ist es der Artikel scheint einen Fehler in ihrem Diagramm hat. Ist das richtig?

Und noch eine Frage: Wo sitzt die wahre Logik für a.foobar? Ich dachte, es war in __getattribute__, aber anscheinend nicht vollständig.

Edit: kein Duplikat

Difference between __getattr__ vs __getattribute__. Ich frage hier, was ist der Unterschied zwischen object.foo und object.__getattribute__("foo"). Dies unterscheidet sich von __getattr__ vs __getatribute__, was trivial ist ...

+1

Zuerst auf das offizielle Dokument verweisen: https://docs.python.org/3.5/reference/datamodel.html#object.__getattribute__ – thodnev

+0

Ändern Sie ein .__ getattribute __ ('foobar') 'in ein .__ getattr __ ('foobar ') 'und sehen, was passiert. – DeepSpace

+0

Nicht daran interessiert ... '__getattribute__' soll schließlich' _getattr__' heißen. 'a.foobar' soll" __getattribute__ "aufrufen – deller

Antwort

4

Es ist einfach zu dem Eindruck, dass __getattribute__ ist verantwortlich für mehr als es wirklich ist. thing.attr übersetzt nicht direkt in thing.__getattribute__('attr') und __getattribute__ ist nicht verantwortlich für den Aufruf __getattr__.

Der Fallback auf __getattr__ passiert in dem Teil der Attributzugriffsmaschinerie, der außerhalb __getattribute__ liegt. Das Attribut-Lookup-Prozess funktioniert wie folgt:

  • Finden Sie die __getattribute__ Methode über eine direkte Suche nach dem MRO der Objekttyp, die reguläre Attribut Nachschlageprozess umgangen wird.
  • Versuchen Sie __getattribute__.
  • Wenn __getattribute__ etwas zurückgegeben wird, ist der Attribut-Lookup-Prozess abgeschlossen, und das ist der Attributwert.
  • Wenn __getattribute__ einen Nicht-Attributfehler ausgelöst hat, ist der Attribut-Lookup-Prozess abgeschlossen, und die Ausnahme wird außerhalb der Suche weitergegeben.
  • Sonst hat __getattribute__ einen AttributeError ausgelöst. Die Suche wird fortgesetzt.
  • Finden Sie die __getattr__ Methode auf die gleiche Weise, wie wir __getattribute__ gefunden haben.
  • Wenn keine __getattr__ vorhanden ist, ist der Attribut-Lookup-Prozess abgeschlossen, und das AttributError von __getattribute__ wird weitergegeben.
  • Versuchen Sie __getattr__, und zurück oder erhöhen, was auch immer __getattr__ zurückgibt oder erhöht.

Zumindest in Bezug auf die Sprache Semantik funktioniert es so. Im Hinblick auf die Implementierung auf niedriger Ebene können einige dieser Schritte in Fällen, in denen sie unnötig sind, optimiert werden, und es gibt C-Hooks wie tp_getattro, die ich nicht beschrieben habe. Sie müssen sich nicht um solche Dinge sorgen, es sei denn, Sie möchten in den CPython-Interpreter-Quellcode eintauchen.

+0

TL; DR '__getattribute__' umgeht die reguläre Attributsuche nur dann, wenn sie definiert ist und nicht zum Aufruf von' __getattr__' gedacht ist. Der Aufruf von '__getattribute__' direkt auf eine Klasse, die ihn nicht definiert, greift auf 'object .__ getattribute__' oder eine andere Basisklasse zurück und löst somit (wahrscheinlich) einen' AttributeError' aus –