3

これは難しい。メソッドを動的に作成するだけでなく、デコレーターを関連付けたい。これは私が試したものです

import inspect
import types

class Dynamo(object):
    pass

def call_me_dec(func):
    print 'I am here'
    return func

def add_dynamo(cls,i):
    # @call_me_dec
    def innerdynamo(self):
        print "in dynamo %d" % i
        return i

    innerdynamo.__doc__ = "docstring for dynamo%d" % i
    innerdynamo.__name__ = "dynamo%d" % i
    setattr(cls, innerdynamo.__name__, innerdynamo)

def add_decorators(cls):
    for name, fn in inspect.getmembers(cls):
        if isinstance(fn, types.UnboundMethodType):
            setattr(cls, name, call_me_dec(fn))

for i in range(2):
    add_dynamo(Dynamo, i)

add_decorators(Dynamo)

d=Dynamo()
d.dynamo0()
d.dynamo1()

出力は次のとおりです。

    I am here
    I am here
    in dynamo 0
    in dynamo 1

期待される出力:

    I am here
    in dynamo 0
    I am here
    in dynamo 1

なぜこれが起こっているのか、どうすれば望ましい結果を得ることができるのかを説明してください。

4

1 に答える 1

5

デコレータコードは、関数が呼び出されたときではなく、装飾された関数の作成時に呼び出されるためです。呼び出し時にコードを実行する場合は、デコレータに、decoratedメソッドを呼び出す呼び出し可能オブジェクト(通常はクロージャ)を返すようにする必要があります。元:

def call_me_dec(func):
    print 'Decorating %s' % func
    def func_wrapper(*args, **kwargs):
        print 'Calling %s' % func
        return func(*args, **kwargs)
    return func_wrapper

デコレータ構文は単なる構文上の糖衣です。覚えて:

def func():
    pass
func = deco(func)

と同等です

@deco
def func():
    pass

いずれにせよ、明示的に定義されたとしてfunc渡されることから返されるオブジェクトを参照するローカル名前空間のラベルになります。デコレータ構文には、いくつかの追加のチェックがバンドルされています(たとえば、入出力が常に呼び出し可能であることを確認するなど)が、基本的に、例1で特定の方法で機能する場合は、例2でもそのように機能します。funcdecodeco

于 2012-09-11T22:17:31.333 に答える