2009-03-12 23 views
5

Angenommen, Sie haben eine Python-Methode, die einen Typ als Parameter erhält; Ist es möglich zu bestimmen, ob der gegebene Typ eine geschachtelte Klasse ist?
Zum Beispiel in diesem Beispiel:Python: Ermitteln, ob eine Klasse geschachtelt ist

def show_type_info(t): 
    print t.__name__ 
    # print outer class name (if any) ... 

class SomeClass: 
    pass 

class OuterClass: 
    class InnerClass: 
     pass 

show_type_info(SomeClass) 
show_type_info(OuterClass.InnerClass) 

würde ich den Anruf zu show_type_info(OuterClass.InnerClass) gerne auch zeigen, dass innerhalb Innerclass OuterClass definiert ist.

+0

Was ist falsch mit Selbst .__ Klasse __.__ Name__? Welchen Zweck haben Sie für diese Information? –

+0

@ S.Lott: was meinst du mit "was ist los mit selbst .__ class __.__ name__"? Sorry, ich verstehe deine Frage nicht ... –

+0

@orsogufo: Was ist "falsch" - funktioniert nicht - ist nicht angemessen - hilft nicht - ist kaputt - tut nicht was Sie wollen - ist nicht im richtigen Format - "falsch" mit Selbst .__ Klasse __.__ Name__? Da stimmt etwas nicht, aber ich weiß nicht, was du nicht magst. Bitte klären Sie. –

Antwort

12

AFAIK, gegeben eine Klasse und keine anderen Informationen, können Sie nicht sagen, ob es eine geschachtelte Klasse ist. Jedoch, see here für wie Sie einen Dekorator verwenden können, um dies zu bestimmen.

Das Problem ist, dass eine verschachtelte Klasse einfach eine normale Klasse ist, die ein Attribut ihrer äußeren Klasse ist. Andere Lösungen, von denen Sie möglicherweise erwarten, dass sie funktionieren, werden wahrscheinlich nicht - inspect.getmro, zum Beispiel, Ihnen nur Basisklassen, keine äußeren Klassen geben.

Auch verschachtelte Klassen werden selten benötigt. Ich würde es noch einmal überdenken, ob das in jedem Fall, in dem Sie versucht sind, eines zu verwenden, ein guter Ansatz ist.

+0

+1 Dies ist ein guter Rat. –

+0

Danke, akzeptiere deine Antwort: Der Punkt ist die Tatsache, dass eine verschachtelte Klasse ein Attribut des Äußeren ist. P.S: Ich bin sicher, es gibt immer Alternativen zu verschachtelten Klassen, aber ich kann nicht verstehen, warum sie auch eine schlechte Idee sein sollten. –

5

Eine innere Klasse bietet keine besonderen Besonderheiten in Python. Es ist nur eine Eigenschaft des Klassenobjekts, die sich nicht von einer Integer- oder String-Eigenschaft unterscheidet. Ihr OuterClass/Innerclass Beispiel kann genau so geschrieben werden:

class OuterClass(): pass 
class InnerClass(): pass 
OuterClass.InnerClass= InnerClass 

Innerclass kann nicht wissen, ob es in einer anderen Klasse deklariert wurde, denn das ist nur eine einfache variable Bindung. Die Magie, die gebundene Methoden über ihren Besitzer "selbst" informiert, trifft hier nicht zu.

Die innere Magie Magie in der Link John veröffentlicht ist ein interessanter Ansatz, aber ich würde es nicht so verwenden wie es ist. Es ist nicht die Klassen-Cache für jedes äußeren Objekt erstellt, so dass Sie eine neue Innerclass jedes Mal erhalten Sie outerinstance.InnerClass nennen:

>>> o= OuterClass() 
>>> i= o.InnerClass() 
>>> isinstance(i, o.InnerClass) 
False # huh? 
>>> o.InnerClass is o.InnerClass 
False # oh, whoops... 

auch so, wie es versucht, das Java-Verhalten macht äußeren Klassenvariablen zu replizieren verfügbar auf der inneren Klasse mit getattr/setattr ist sehr zweifelhaft, und unnötig wirklich (da die mehr Pythonic Weg wäre, i .__ äußere __. attr explizit zu nennen).

0

Wenn Sie es nicht selbst festlegen, glaube ich nicht, dass es eine Möglichkeit gibt festzustellen, ob die Klasse verschachtelt ist. Da eine Python-Klasse sowieso nicht als Namespace (oder zumindest nicht einfach) verwendet werden kann, würde ich sagen, dass es am einfachsten ist, verschiedene Dateien zu verwenden.

4

Wirklich eine geschachtelte Klasse unterscheidet sich nicht von irgendeiner anderen Klasse - sie wird einfach irgendwo anders definiert als der Namespace der obersten Ebene (innerhalb einer anderen Klasse). Wenn wir die Beschreibung von "verschachtelt" auf "nicht auf oberster Ebene" ändern, können Sie nahe genug an das heranreichen, was Sie brauchen.

zB:

import inspect 

def not_toplevel(cls): 
    m = inspect.getmodule(cls) 
    return not (getattr(m, cls.__name__, []) is cls) 

Dies wird für gemeinsame Fällen funktionieren, aber es kann nicht tun, was Sie in Situationen wollen, wo Klassen umbenannt werden oder auf andere Weise nach Definition manipuliert. Zum Beispiel:

class C:    # not_toplevel(C) = False 
    class B: pass # not_toplevel(C.B) = True 

B=C.B    # not_toplevel(B) = True 

D=C     # D is defined at the top, but... 
del C    # not_toplevel(D) = True 

def getclass():  # not_toplevel(getclass()) = True 
    class C: pass 
1

Vielen Dank für Ihre Antworten.
Ich habe diese mögliche Lösung mit Metaklassen gefunden; Ich habe es mehr für die Obstinierung als für das wirkliche Bedürfnis getan, und es ist auf eine Weise gemacht, die für Python 3 nicht anwendbar ist.
Ich möchte diese Lösung trotzdem teilen, also poste ich sie hier.

#!/usr/bin/env python 
class ScopeInfo(type): # stores scope information 
    __outers={} # outer classes 
    def __init__(cls, name, bases, dict): 
     super(ScopeInfo, cls).__init__(name, bases, dict) 
     ScopeInfo.__outers[cls] = None 
     for v in dict.values(): # iterate objects in the class's dictionary 
      for t in ScopeInfo.__outers: 
       if (v == t): # is the object an already registered type? 
        ScopeInfo.__outers[t] = cls 
        break; 
    def FullyQualifiedName(cls): 
     c = ScopeInfo.__outers[cls] 
     if c is None: 
      return "%s::%s" % (cls.__module__,cls.__name__) 
     else: 
      return "%s.%s" % (c.FullyQualifiedName(),cls.__name__) 

__metaclass__ = ScopeInfo 

class Outer: 
    class Inner: 
     class EvenMoreInner: 
      pass 

print Outer.FullyQualifiedName() 
print Outer.Inner.FullyQualifiedName() 
print Outer.Inner.EvenMoreInner.FullyQualifiedName() 
X = Outer.Inner 
del Outer.Inner 
print X.FullyQualifiedName() 
Verwandte Themen