1

実行時に既存のクラスに新しいクラスを追加しようとしています(「type(...)」を使用)。また、新しいクラスにない属性に対して独自の動作を実行できるように、その新しいクラスの__getattr__をオーバーライドしようとしています。たとえば、クラスfooがあり、クラス "tool"を追加し、foo.tool.testに独自の処理を実行させたいとします。以下のコードは機能しますが、部分的にしか機能しません。明示的に__getattr__を呼び出すと機能しますが(最初の印刷を参照)、foo.tool.testを参照すると、オーバーライドされた__getattr__が呼び出されず、属性エラーが発生します。

あなたの助けは大歓迎です。

class Foo(object):
    def __init__(self):
        self.NameList=[]
        # add new class to ourself
        self.tool = type('tool', (object,), {} )
        # override new class' __getattr__ with call to ourself
        setattr(self.tool, "__getattr__", self.__getattr__ )
        # add one well known test name for now
        self.NameList.append( "test" )

    # should be called by our newly added "tool" object but is only called sometimes...
    def __getattr__(self, attr):
        # print( "__getattr__: %s" % attr )
        if( attr in self.NameList ):     
            return( 99 )
        raise AttributeError("--%r object has no attribute %r" % (type(self).__name__, attr))       

foo = Foo()
# access tool class attribute "test" - it should be seen by the override __getattr__
# the following works...
print( "foo.tool.__getattr__=%d" % foo.tool.__getattr__("test") )  
# but the following does not - why is this not the same as the line above???
print( "foo.tool.test=%d" % foo.tool.test )                         
4

1 に答える 1

6

Python は、インスタンスの ではなく、__getattr__インスタンスの bases のような特別なメソッドを探します。__dict____dict__

self.toolクラスです。self.tool.testしたがって、 は __getattr__ofself.toolのクラス (つまり) を呼び出しますobject。これは、私たちが望んでいることではありません。

代わりに、self.toolクラスが を持つインスタンスを作成し__getattr__ます。

class Foo(object):
    def __init__(self):
        self.NameList=[]
        # add new class to ourself
        toolcls = type('tool', (object,), { '__getattr__' : self.__getattr__, } )
        self.tool = toolcls()
        self.NameList.append( "test" )

    # should be called by our newly added "tool" object but is only called sometimes...
    def __getattr__(self, attr):
        # print("__getattr__: (%s, %s)" % (self.__class__.__name__, attr) )
        if( attr in self.NameList ):     
            return( 99 )
        raise AttributeError("--%r object has no attribute %r" % (
            type(self).__name__, attr)) 

foo = Foo()
print( "foo.tool.__getattr__=%d" % foo.tool.__getattr__("test") )
print( "foo.tool.test=%d" % foo.tool.test )    

収量

foo.tool.__getattr__=99
foo.tool.test=99

また、 のインスタンスが定義さFooれずに作成された場合、上記のコードは無限再帰につながる可能性があることに注意してください。この驚くべき落とし穴に関する Ned Batchelder の投稿をself.NameList参照してください。

ここで無限再帰の可能性を防ぐには、次を使用します。

def __getattr__(self, attr):
    # print("__getattr__: (%s, %s)" % (self.__class__.__name__, attr) )
    if attr == 'NameList':
        raise AttributeError()
    if( attr in self.NameList ):     
        return( 99 )
    raise AttributeError("--%r object has no attribute %r" % (
        type(self).__name__, attr)) 
于 2012-11-30T02:25:26.127 に答える