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_call def foo(b, a=[]): if b: a.append(3) return a import timeit

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

[3]
[3]

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

@compute_default_value_for_each_call
def foo(b, a=[]):
    if b:
        a.append(3)
    return a


def foo2(b, a=None):
    a = a or []
    if b:
        a.append(3)
    return a

import timeit

print 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.32704997063
0.630109071732
0.445858955383
0.26370882988

性能上还过得去....

python 在调用时计算默认值,布布扣,bubuko.com

python 在调用时计算默认值

上一篇:java定时任务类Timer和TimerTask用法详解


下一篇:[XPath/Python] XPath 与 lxml (二)XPath 语法