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

尽管检查可能会让您有所了解,但您想要的通常是不可能的:

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 Martellikwargs.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 回答