首页 > 代码库 > python 在调用时计算默认值

python 在调用时计算默认值

大家都知道python的默认值是在函数定义时计算出来的, 也就是说默认值只会计算一次, 之后函数调用时, 如果参数没有给出,
同一个值会赋值给变量, 这会导致, 如果我们想要一个list默认值, 新手通常这么写:

def foo(a=[]): a.append(3) print a

其实是错误的,两次调用会这样的结果:

[3][3, 3]

其实应该这么写

def baz(a=None):
  a = a or []
a.append(3) print a

两次调用输出以下结果:

[3][3]

 

 

这样好挫啊, 搞的虽然有默认值用法,但是我们却需要写的和js,lua一样, 我们不能像c++一样, 在函数运行时每次执行默认值么.
用decorator可以模拟下

import functools
import copy
def
compute_default_value_for_each_call(func): defaults = func.__defaults__ if not defaults: return None defaults = tuple(copy.copy(x) for x in defaults) @functools.wraps(func) def wrapper(*args, **kwargs): if func.__defaults__ != defaults: func.__defaults__ = tuple(copy.copy(y) for y in defaults) return func(*args, **kwargs) return wrapper@compute_default_value_for_each_calldef foo(b, a=[]): if b: a.append(3) return aimport timeit

这样两次调用foo(1), 结果为:

[3][3]

这个decorator有对未修改默认参数值做优化, 在我们不对默认值修改的情况下(比如打印变量a的内容), 性能有很大提升:

@compute_default_value_for_each_calldef foo(b, a=[]):    if b:        a.append(3)    return adef foo2(b, a=None):    a = a or []    if b:        a.append(3)    return aimport timeitprint timeit.timeit(foo(1), setup=from __main__ import foo)print timeit.timeit(foo(0), setup=from __main__ import foo)print timeit.timeit(foo2(1), setup=from __main__ import foo2)print timeit.timeit(foo2(0), setup=from __main__ import foo2)

执行结果(调用1000000次的总时间)

4.327049970630.6301090717320.4458589553830.26370882988

性能上还过得去....