2016-06-30 10 views
3

diesen Code vor:Python: Wie Namespaces zugreifen äußeren Klasse

class A: 
     B = 42 # or whatever 
     class C: 
       a = B # wont find `B` here 

Das ist nicht, weil in class C funktionieren wird, es wird nicht B finden.

Sie können auch nicht A.B verwenden, weil auch A zu diesem Zeitpunkt nicht bekannt ist, da es noch erstellt wird und daher nicht im globalen Namespace ist. In einer Member-Funktion würde das funktionieren, denn an dem Punkt, an dem Sie diesen Code ausführen, wird wahrscheinlich der globale Name A registriert. Ich bitte jedoch explizit um den direkten Zugriff, nicht innerhalb einer Member-Funktion.

Gibt es in solchen verschachtelten Klassenkonstrukten also einen anderen Weg, auf die äußeren Namespaces zuzugreifen?

Ich denke, die Antwort könnte Nein sein, oder zumindest nicht auf eine saubere Art und Weise. Ich fügte print(locals()) innerhalb von class C und mit Python 2, ich bekomme {'__module__': '__main__'}, mit Python 3, bekomme ich {'__qualname__': 'A.C', '__module__': '__main__'}. Also weder die Einheimischen noch die Globals geben mir den Zugriff auf den übergeordneten lokalen Namespace.

Über einen nicht sauberen Weg: sys._getframe(1).f_locals["B"] wird funktionieren. Das sind die Einheimischen der Klasse A, während es gebaut wird, und B ist dort drin.

Also, wenn es keine saubere Möglichkeit gibt, das zu tun, was sind andere Lösungen? Ich könnte alle Klassen direkt im globalen Namensraum deklarieren, aber das mag ich nicht (für meinen speziellen Anwendungsfall). Ich könnte sie in ein Submodul verschieben und sie in A importieren. Aber das macht den Code komplizierter zu lesen. Irgendwelche anderen Lösungen?


Also, ich denke, es ist immer das gleiche, wenn ich nicht ein reales Beispiel zeigen kann, werden die Menschen nicht glauben, wie ein solcher Anwendungsfall passieren kann. So, hier ist es (via):

class structs: 
    # .... many more 

    class _anonymous_label(ctypes.Structure): 
     _fields_ = [ 
      ('lb_type', ctypes.c_int), 
      ('lb_str', ctypes.POINTER(ctypes.c_byte))] 

    class _anonymous_labellist(ctypes.Structure): 
     _fields_ = [ 
      ('ll_nlabels', ctypes.c_int), 
      ('ll_label', ctypes.POINTER(_anonymous_label))] # error 

    # .... many more 
+0

Sehen Sie, wie das Beispiel trivial ist: welchen Anwendungsfall haben Sie, wo das nicht trivial ist? – MisterMiyagi

+2

Ich bin eigentlich ein bisschen neugierig. Wie unterscheidet sich das von einer Schließung? Wo hat die innere Funktion Zugriff auf den äußeren Bereich? Ich spielte mit der Verwendung einer Metaklasse herum und benutzte seine ** \ __ new \ __ **, um C.a = B zu setzen, aber selbst das war erstickend - * der globale Name 'B' ist nicht definiert *. Ich weiß, dass eine Klassendeklaration per se keine Funktion ist, aber der Scopingaspekt "sieht gleich aus". Hat Python 3 (ich bin auf 2) auch die Suche nach Verschachtelungsbereichen geändert? –

+1

'Klassenstrukturen: ...' - warum würdest du das tun? Auch wenn Sie möchten, dass die darin enthaltenen Klassen in ihrem eigenen Namespace liegen, ist dies eine Aufgabe für das Modulsystem, keine verschachtelten Klassen. Mach ein 'structs' Modul. – user2357112

Antwort

1
class Constants: 
    a = 1 

class A: 
    class B(Constants): 
     pass 

    class C(Constants): 
     pass 

print(A.B.a, A.C.a) 
+0

Sie teilen nicht die gleichen Basiskonstanten. In meinem Beispiel war es nur zufällig, dass der Attributname derselbe war. – Albert

1

ich die Klasse führen würde Variablenzuweisungen für die inneren Klassen in der äußeren Klasse nach die inneren Klassendeklarationen vollständig sind. Es ist sehr wenig komplizierter, ganz offensichtlich, und es funktioniert:

class A: 
    class B: 
     a = 1 
    class C: 
     pass 
    C.a = B.a 

print(A.B.a, A.C.a) 
+1

Leider funktioniert das nicht für meinen Fall, weil die Klassenkonstruktion beendet werden muss (weil es 'ctypes.Structure' ist). Code-Editoren werden das auch nicht, wenn das Attribut member außerhalb definiert ist. – Albert

0

Was denken Sie über

var = 1 
class A: 
    class B: 
     a = var 
    class C: 
     a = var 
+0

Ich muss auf 'B' verweisen, keine allgemeine Konstante global wie' var'. – Albert

0

Sie können immer mit temporären Objekten arbeiten, die Sie nicht aussetzen. Abhängig davon, wie Ihr nicht-triviales Beispiel aussieht, ist dies jedoch möglicherweise nicht angemessen.

# foo module 
ABC_ATTRIBUTE = 42 
class A: 
    B = ABC_ATTRIBUTE 
    class C: 
    a = ABC_ATTRIBUTE 
del ABC_ATTRIBUTE # no longer accessible as foo.ABC_ATTRIBUTE 
+1

Das meinte ich, als ich sagte "Ich könnte alle Klassen direkt im globalen Namensraum deklarieren". – Albert

+0

@Albert Ich sehe, Ihr hinzugefügtes Beispiel macht deutlich, warum Sie das nicht wollen. Ich brauche keine 'class struct', aber das ändert nichts an dem Problem, das Sie gelöst haben wollen. – MisterMiyagi

+0

Weil ich nicht möchte, dass sich alle Mitglieder im globalen Namespace befinden. Wie in Ihrem Beispiel könnte ich am Ende eine große Liste von "del xy" haben, aber das scheint eine etwas hässliche Lösung zu sein. – Albert

Verwandte Themen