6

私は自分がコーディングした Python 関数のパフォーマンスを測定できるのが好きなので、これに似たことを頻繁に行います...

import time

def some_function(arg1, arg2, ..., argN, verbose = True) :
    t = time.clock() # works best in Windows
    # t = time.time() # apparently works better in Linux

    # Function code goes here

    t = time.clock() - t
    if verbose :
        print "some_function executed in",t,"sec."

    return return_val

はい、timeit を使用してパフォーマンスを測定することになっていることは承知していますが、これは私のニーズには問題なく機能し、デバッグのためにこの情報のオンとオフを非常にスムーズに切り替えることができます。

もちろん、そのコードは私が関数デコレーターについて知る前からのものでした...私は今それらについてあまり知りませんが、 **kwds 辞書を使用して、次のことを行うデコレーターを書くことができると思います:

some_function(arg1, arg2, ..., argN) # Does not time function
some_function(arg1, arg2, ..., argN, verbose = True) # Times function

それにもかかわらず、関数の以前の作業を複製して、作業が次のようになるようにしたいと思います。

some_function(arg1, arg2, ..., argN) # Does not time function
some_function(arg1, arg2, ..., argN, False) # Does not time function
some_function(arg1, arg2, ..., argN, True) # Times function

これには、デコレータが引数の数を数え、元の関数がいくつ取るかを知り、余分なものを取り除き、それらの正しい数を関数に渡す必要があると思います... Pythonに伝える方法はわかりませんこれを行うには...それは可能ですか?同じことを達成するより良い方法はありますか?

4

3 に答える 3

9

inspectを使えば少しは進むかもしれませんが、一般的には、あなたが望むことは不可能です:

def f(*args):
    pass

では、いくつの引数がf必要ですか? 任意の数の引数*argsを許可するため、関数が必要とする引数の数を決定する方法はありません。**kwargs実際、関数がスローされた数だけ実際に処理する場合があります。


編集:verbose特別なキーワード引数として我慢したい場合は、これを行うことができます:

import time

def timed(f):
    def dec(*args, **kwargs):
        verbose = kwargs.pop('verbose', False)
        t = time.clock()

        ret = f(*args, **kwargs)

        if verbose:
            print("%s executed in %ds" % (f.__name__, time.clock() - t))

        return ret

    return dec

@timed
def add(a, b):
    return a + b

print(add(2, 2, verbose=True))

(ヒントをくれたAlex Martelliに感謝します!)kwargs.pop

于 2009-05-20T17:12:34.057 に答える
8

ただし、Stephan202の回答に+1します(コメントはコードを適切にフォーマットしないため、これを別の回答に入れます!)、その回答の次のコードのビット:

verbose = False
if 'verbose' in kwargs:
     verbose = True
     del kwargs['verbose']

次のように、より明確かつ簡潔に表現できます。

verbose = kwargs.pop('verbose', False)
于 2009-05-20T17:34:31.093 に答える
0

難しいかもしれませんが、これらの行で何かを行うことができます。以下のコードは、余分な引数を削除して出力しようとします。

def mydeco(func):
    def wrap(*args, **kwargs):
        """
        we want to eat any extra argument, so just count args and kwargs
        and if more(>func.func_code.co_argcount) first take it out from kwargs 
        based on func.func_code.co_varnames, else last one from args
        """
        extraArgs = []

        newKwargs = {}
        for name, value in kwargs.iteritems():
            if name in func.func_code.co_varnames:
                newKwargs[name] = value
            else:
                extraArgs.append(kwargs[name])

        diff = len(args) + len(newKwargs) - func.func_code.co_argcount
        if diff:
            extraArgs.extend(args[-diff:])
            args = args[:-diff]

        func(*args, **newKwargs)
        print "%s has extra args=%s"%(func.func_name, extraArgs)

    return wrap

@mydeco
def func1(a, b, c=3):
    pass

func1(1,b=2,c=3, d="x")
func1(1,2,3,"y")

出力は

func1 has extra args=['x']
func1 has extra args=['y']
于 2009-05-20T17:34:34.933 に答える