python: a determina dacă o clasă este imbricat

voturi
5

Să presupunem că aveți o metodă de piton care devine un tip ca parametru; este posibil să se determine dacă tipul dat este o clasă imbricată?
De exemplu , în acest exemplu:

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)

Aș dori apelul la show_type_info(OuterClass.InnerClass)a arăta , de asemenea , că InnerClass este definit în interiorul OuterClass.

Întrebat 12/03/2009 la 14:26
sursa de către utilizator
În alte limbi...                            


6 răspunsuri

voturi
12

AFAIK, având în vedere o clasă și nici o altă informație, nu puteți spune dacă este sau nu este o clasă imbricată. Cu toate acestea, a se vedea aici pentru modul în care s - ar putea folosi un decorator pentru a determina acest lucru.

Problema este că o clasă imbricată este pur și simplu o clasă normală , care este un atribut al clasei sale exterioare. Alte soluții care v - ar aștepta să lucreze , probabil , nu vor - inspect.getmro, de exemplu, vă oferă numai clase de bază, nu clase exterioare.

De asemenea, clase imbricate sunt rareori necesare. Mi-ar reconsidera cu tărie că dacă este o bună abordare în fiecare caz particular, în cazul în care te simți tentat să utilizați una.

Publicat 12/03/2009 la 14:34
sursa de către utilizator

voturi
5

O clasă internă nu oferă caracteristici speciale particulare în Python. Este doar o proprietate a obiectului de clasă, nu este diferit de un întreg șir de caractere sau a proprietății. Exemplul dumneavoastră OuterClass / InnerClass poate fi rescrisă exact ca:

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

InnerClass nu poate ști dacă acesta a fost declarat într-o altă clasă, pentru că e doar o variabilă de legare simplu. Magia care face metode legate știu despre „sine“, proprietarul lor nu se aplică aici.

Magia InnerClass decorator în link-ul postat John este o abordare interesantă, dar nu mi-ar folosi așa cum este. Aceasta nu cache clasele pe care le creează pentru fiecare obiect exterior, astfel încât să obțineți un nou InnerClass de fiecare dată când suni outerinstance.InnerClass:

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

De asemenea, modul în care încearcă să reproducă comportamentul Java de a face variabile ale clasei exterioare disponibile pe clasa de interior cu getattr / setattr este foarte dubios, și inutile într-adevăr (din moment ce mod mai pythonic ar fi de a apela i .__ exterior __. ATTR în mod explicit).

Publicat 12/03/2009 la 15:23
sursa de către utilizator

voturi
0

Dacă nu setați-le, eu nu cred că există vreo modalitate de a determina dacă clasa este imbricat. Ca oricum o clasă Python nu poate fi folosit ca un spațiu de nume (sau cel puțin nu cu ușurință), aș spune că cel mai bun lucru de făcut este pur și simplu utilizați fișiere diferite.

Publicat 12/03/2009 la 15:37
sursa de către utilizator

voturi
4

Într-adevăr o clasă imbricată nu este diferită de orice altă clasă - pur și simplu se întâmplă să fie definit în altă parte decât spațiul de nume de nivel superior (într-o altă clasă de schimb). Dacă vom modifica descrierea de la „imbricate“ la „nivel non-top“, atunci s-ar putea fi capabil de a veni destul de aproape de ceea ce ai nevoie.

de exemplu:

import inspect

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

Acest lucru va lucra pentru cazurile comune, dar nu poate face ceea ce doriți în situațiile în care clasele sunt redenumite sau manipulate în alt mod după definiție. De exemplu:

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
Publicat 12/03/2009 la 15:46
sursa de către utilizator

voturi
1

Vă mulțumesc tuturor pentru răspunsurile dumneavoastră.
Am găsit această soluție posibilă folosind metaclasses; Am făcut -o mai mult pentru obstination decât nevoia reală, și se face într - un mod care nu vor fi aplicabile la Python 3.
Vreau să împărtășesc această soluție , oricum, așa că - l posta aici.

#!/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()
Publicat 12/03/2009 la 16:14
sursa de către utilizator

voturi
0

Începând cu Python 3.3 este un atribut nou __qualname__, care oferă nu numai numele de clasă, dar , de asemenea , numele claselor exterioare:

În proba acest lucru ar avea ca rezultat:

assert SomeClass.__qualname__ == 'SomeClass'
assert OuterClass.InnerClass.__qualname__ == 'OuterClass.InnerClass'

În cazul în care __qualname__dintr - o clasă nu conține o „“ este o clasă exterioară!

Publicat 22/04/2018 la 17:53
sursa de către utilizator

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more