6

パラメータとして型を取得する python メソッドがあるとします。指定された型がネストされたクラスであるかどうかを判断することは可能ですか?
たとえば、この例では:

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)

show_type_info(OuterClass.InnerClass)InnerClass が OuterClass 内で定義されていることも示すように呼び出したいと思います。

4

6 に答える 6

13

私の知る限り、クラスがあり、他の情報がない場合、それがネストされたクラスであるかどうかはわかりません。ただし、これを決定するためにデコレータを使用する方法については、こちらを参照してください。

問題は、ネストされたクラスが、その外側のクラスの属性である単なる通常のクラスであることです。動作すると予想される他のソリューションは、おそらく動作しませんinspect.getmro。たとえば、外部クラスではなく、基本クラスのみが提供されます。

また、ネストされたクラスが必要になることはほとんどありません。使用したくなる特定のケースごとに、それが良いアプローチであるかどうかを強く再考します。

于 2009-03-12T15:34:51.020 に答える
5

内部クラスは、Python で特定の特別な機能を提供しません。これはクラス オブジェクトの単なるプロパティであり、整数または文字列プロパティと同じです。OuterClass/InnerClass の例は、次のように正確に書き直すことができます。

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

InnerClass は、それが別のクラス内で宣言されているかどうかを知ることができません。これは単なる変数バインディングであるためです。バインドされたメソッドに所有者の「自己」を知らせる魔法は、ここでは適用されません。

John が投稿したリンクの内部クラス デコレータ マジックは興味深いアプローチですが、そのままでは使用しません。外側のオブジェクトごとに作成するクラスをキャッシュしないため、outerinstance.InnerClass を呼び出すたびに新しい InnerClass を取得します。

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

また、getattr/setattr を使用して外部クラス変数を内部クラスで使用可能にするという Java の動作を複製しようとする方法は非常に危険であり、実際には不必要です (より Python 的な方法は i.__outer__.attr を明示的に呼び出すことであるため)。

于 2009-03-12T16:23:04.447 に答える
4

実際、ネストされたクラスは他のクラスと何ら変わりはありません。たまたまトップレベルの名前空間以外の場所(代わりに別のクラス内)で定義されているだけです。説明を「ネスト」から「非トップレベル」に変更すると、必要なものに十分に近づくことができる場合があります。

例えば:

import inspect

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

これは一般的なケースでは機能しますが、クラスの名前が変更されたり、定義後に操作されたりする状況では、希望どおりに機能しない場合があります。例えば:

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
于 2009-03-12T16:46:50.987 に答える
1

回答ありがとうございます。
メタクラスを使用してこの可能な解決策を見つけました。私は実際の必要性よりも執念のためにそれを行いました.Python 3
には適用できない方法で行われました.とにかくこの解決策を共有したいので、ここに投稿します.

#!/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()
于 2009-03-12T17:14:20.250 に答える
0

自分で設定しないと、クラスがネストされているかどうかを判断する方法がないと思います。いずれにせよ、Python クラスを名前空間として使用することはできません (または、少なくとも簡単には使用できません)。最善の方法は、単に別のファイルを使用することです。

于 2009-03-12T16:37:15.567 に答える