2010-09-06 30 views
30

Ich war überrascht, zu erfahren, dass eine Klassenvariable einer Unterklasse nicht eine Klassenvariable des Mutter zugreifen kann, ohne die Klassennamen der Mutter speziell angibt:Python Unterklasse Zugriff auf Klassenvariable der Eltern

>>> class A(object): 
...  x = 0 
... 
>>> class B(A): 
...  y = x+1 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in B 
NameError: name 'x' is not defined 
>>> class B(A): 
...  y = A.x + 1 
... 
>>> B.x 
0 
>>> B.y 
1 

Warum definiere ich bei der Definition von "Ich muss mich auf Ax beziehen und nicht nur auf x?" Dies widerspricht meiner Intuition aus Instanzvariablen, und da ich nach Definition von B auf B.x verweisen kann.

Antwort

24

In Python wird der Body einer Klasse in einem eigenen Namespace ausgeführt, bevor die Klasse erstellt wird (danach werden die Member dieses Namespace die Member der Klasse). Wenn also der Interpreter y = x + 1 erreicht, existiert Klasse B zu diesem Zeitpunkt noch nicht und hat daher kein Elternteil.

Weitere Einzelheiten finden Sie http://docs.python.org/reference/compound_stmts.html#class-definitions

47

für barenames Scoping-Regeln Pythons sind sehr einfach und unkompliziert: lokaler Namensraum zuerst, dann (falls vorhanden) Außen Funktionen, in denen die aktuellen verschachtelt sind, dann Globals schließlich integriert ins. Das ist alles, was passiert, wenn ein Deckname gesucht wird und es keine Notwendigkeit gibt, komplizierte Regeln zu merken oder anzuwenden (noch ist es für einen Python-Compiler nötig, kompliziertere Regeln zu erzwingen).

Alle Sie Zeit, einen anderen Nachschlag mag, erhalten Sie ein qualifizierte Namen verwenden, keine nackte Namen. Qualifizierte Namen sind erheblich leistungsfähiger, da die Suche immer an die Objekte delegiert werden kann, deren Attribute angefordert werden können, und diese Objekte können alle erforderlichen Suchregeln implementieren. Insbesondere in einer Instanz Methode innerhalb einer Klasse self.x ist die Weise, das self Objekt zu bitten, Attributnamen 'x' nachzuschlagen - und in dieser Suche kann es an Klassen delegieren, einschließlich der Implementierung des Konzepts der Vererbung (und Mehrfachvererbung, Reihenfolge der Methodenauflösung usw.).

Der Körper eine Klasse (wie in einer Klasse definiert, um den Körper der Verfahren gegen) führt als Teil der class Anweisung vor das Klassenobjekt erstellt wird oder der Name gebunden ist (insbesondere bevor irgendeine der Basen als Basen definiert wurde - obwohl dieses letzte Detail bei der Bezugnahme auf Barnamen sowieso keine Rolle spielen kann! -).

Also, in Ihrem Beispiel, in Klasse B, wird der Name x mit den universellen Regeln nachgeschlagen - ist es ein lokal gebundener Name? Wenn nein, ist es in irgendeiner äußeren Funktion gebunden, in der dieser Bereich verschachtelt ist? Wenn nein, ist es als global oder integriert gebunden? Wenn keiner der oben genannten Fälle auftritt, verursacht das Verwenden des fraglichen Namesamens natürlich eine Namensfehlerausnahme.

Da Sie eine andere Nachschlage-Sequenz als die Barname-Lookup-Regeln universell erzwingen möchten, dann müssen Sie eindeutig einen qualifizierten Namen, nicht einen Barnamen verwenden; und ein Moment der Reflexion wird klar zeigen, dass die "eine offensichtliche Wahl" für einen qualifizierten Namen für Ihren Zweck A.x sein muss - da Sie wollen es nachgeschlagen werden soll (die Grundlagen wurden nirgends aufgezeichnet noch an diesem Punkt, nach alle ... es wird die Metaklasse sein, normalerweise type, die die Basen-Bindung als Teil seiner Arbeit tun wird, wenn es nach aufgerufen wird der Klassenkörper ausgeführt wird! -).

Einige Leute sind so sehr an andere "magische" Regeln für das Nachschlagen von Barnamen gebunden, dass sie diesen Aspekt von Python einfach nicht ertragen können (ursprünglich inspiriert, wie ich glaube, von Modula-3, einer wenig bekannten Sprache) in den Kreisen der Theoretiker wohlüberlegt ;-) - self.x in einer Methode schreiben zu spezifizieren, dass x auf self nachgeschlagen werden muss, anstatt die universellen barename Regeln zu verwenden, fährt zum Beispiel solche Leute batty.

ich, ich liebe die Einfachheit und Universalität der barename Lookup-Regeln, und ich liebe statt barenames qualifizierte Namen jederzeit ich will jede andere Form von Lookup ... aber dann, es ist kein Geheimnis, dass ich Bin wahnsinnig verliebt in Python (; ich habe meine eigenen Grummels - zB global x als Statement mache immer meine Skin Crawl, wo ich lieber global.x schreiben würde, also global einen eingebauten Namen für "die aktuell" habe Ausführungsmodul "... ich do liebe qualifizierte Namen! -), ist es? -)

+1

Wow, danke für die super detaillierte Antwort! –

+1

@Jeff, gern geschehen. –

+4

Aber was ist, wenn Ihre Unterklasse eine Kette von Superklassen hat? Dann verlangt der qualifizierte Name, dass Sie wissen, in welcher Oberklasse die Klassenvariable gesetzt ist. Sicher, ich kann Fälle sehen, in denen diese Anforderung die Dinge sicherer macht, aber auch in einigen Fällen, wo es einschränkend ist. Es scheint, als wäre es schön, ein Äquivalent von 'Super' für Klassenvariablen zu haben. –

Verwandte Themen