2

次のコード フラグメントを検討してください。

def print_timing(func):
    import time
    def wrapper(*args, **kwargs):
        t1 = time.time()
        res = func(*args, **kwargs)
        t2 = time.time()
        print '%s took %0.3f s ~ %0.0f min and %0.1f sec' % (func.func_name, t2-t1, int(t2 - t1)/60, (t2-t1) % 60 )
        return res
    return wrapper

@print_timing                                                                      |
def foo():                                                                         |
    return 'foo' 

class name(object):
       def __init__(self, name):
              self.name = name
       @print_timing
       def __call__(self):
              return self.name

bar = name("bar")
print bar()

これは以下を返します:

__call__ took 0.000 s ~ 0 min and 0.0 sec
bar

このオブジェクトbarは と呼ばれる関数のように動作しますが、デコレータと一緒に使用するとbar内部実装の詳細が公開されます。オブジェクトを変更する方法はありますか(おそらく関数に適切な引数を渡すことによって)、代わりに戻ります__call__print_timingname__init__

 bar took 0.000 s ~ 0 min and 0.0 sec

? print_timingデコレータが通常の機能を引き続き使用できるようにするソリューションが必要です。ランニング print foo()は与える

foo took 0.000 s ~ 0 min and 0.0 sec
foo
4

3 に答える 3

1

メソッドでのみデコレータを使用する限り、それらはself最初の引数として渡されます。

def print_timing(func):
    import time
    def wrapper(*args, **kwargs):
        t1 = time.time()
        res = func(*args, **kwargs)
        t2 = time.time()
        funcname = func.__name__
        # Special case; a "name" instance has a "name" attribute we want to use instead.
        if len(args) >= 1 and isinstance(args[0], name):
            funcname = args[0].name
        print '%s took %0.3f s ~ %0.0f min and %0.1f sec' % (funcname, t2-t1, int(t2 - t1)/60, (t2-t1) % 60 )
        return res
    return wrapper

更新:ラッパーはfunc.__name__デフォルトで使用するようになりましたが、これをnameクラスで使用する場合(元の質問のように)、name代わりにインスタンスの属性を使用します。

isinstanceテストを使用してname属性が存在することを確認しましたが、代わりにダックタイピングを使用できます(if hasattr(args[0], 'name')); 変数は非常に一般的ですが、name任意のクラスメソッドで使用すると予期しない結果が生じる可能性があります。

于 2011-05-28T21:20:22.000 に答える
1

@print_timingクラス デコレータとして使用します。

@print_timing
class name(object):
    ...

変更は必要ありません。あなたのラップされたオブジェクトは、クラスであるはずだったときに関数になりましたが、あなたの質問 (およびそれが呼び出し可能なクラスであるという事実) から、それは実際には問題ではないと推測します (もしそうなら、デコレータを次のように変更できます)。返されたラップされたオブジェクトを「きれいに」します)。

于 2011-05-28T21:49:12.907 に答える
1

いいえ。デコレータはクラスの構築__init__()時に発生し、呼び出しはインスタンスの構築時に発生します。デコレーターに関数を記述子に変換させ、その記述子にインスタンスから名前を取得させる必要があります。

于 2011-05-28T20:58:10.817 に答える