2009-03-12 7 views
5

パラメータを型として取得するpythonメソッドがあるとします。指定された型がネストされたクラスであるかどうかを判断することは可能ですか?
など。この例では: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) 

私はInnerClassがOuterClass内で定義されていることも示すことshow_type_info(OuterClass.InnerClass)への呼び出しをしたいと思います。

+0

self .__ class __.__ name__に問題がありますか?この情報の目的は何ですか? –

+0

@ S.Lott: "自己___クラス__.__ name__"の何が間違っているの?申し訳ありませんが、私はあなたの質問を理解していません... –

+0

@orsogufo:何が "間違って" - 動作しません - 適切ではない - 助けにはならない - 壊れている - 何もしないあなたは欲しい - 正しいフォーマットではない - 自分自身で「間違っている」.__ class __.__ name__?それには何か問題はありますが、あなたが気に入らないものはわかりません。どうか明らかにしてください。 –

答えて

12

AFAIKは、クラスと他の情報がないので、ネストされたクラスであるかどうかを判断できません。ただし、これを決定するためにデコレータを使用する方法については、see hereを参照してください。

ネストされたクラスは、単にその外部クラスの属性である通常のクラスに過ぎないという問題があります。たとえば、inspect.getmroは、外部クラスではなく、基本クラスのみを提供します。

また、ネストされたクラスはめったに必要ありません。私は、それがあなたが1つを使用するように誘惑されると感じるそれぞれの特定のケースにおいて、それが良いアプローチであるかどうかを強く再考するだろう。

+0

+1これは良いアドバイスです。 –

+0

ありがとう、あなたの答えを受け入れる:ポイントは、ネストされたクラスが外側の属性であるということです。 P.S:ネストされたクラスには常に選択肢があると確信していますが、なぜそれらが悪い考えであるべきかはわかりません。 –

5

内部クラスは、Pythonでは特に特別な機能はありません。これはクラスオブジェクトの唯一のプロパティであり、整数または文字列プロパティとは異なります。それが結合単なる変数だからInnerClassが、それは別のクラス内で宣言されたかどうかを知ることができない

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

:あなたのOuterClass/InnerClassの例では、まったく同じように書き換えることができます。バインドされたメソッドを所有者の自己について知る魔法は、ここでは適用されません。

リンク先のJohnの内装デコレータの魔法は興味深いアプローチですが、そのまま使用することはありません。あなたは新しいInnerClassあなたがouterinstance.InnerClass呼び出すたびに取得するように、それは、それはそれぞれの外側のオブジェクトのために作成したクラスをキャッシュしません:

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

それは外側のクラス変数を作るのJavaの動作を複製しようとする方法を内部クラスでgetattr/setattrで利用できるのは非常に厄介で、不要です(もっとPythonの方法はi .__ outer __。attrを明示的に呼び出すためです)。

0

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

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 
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() 
関連する問題