关于Python中函数默认参数的研究

来源:互联网 发布:excel找出重复数据 编辑:程序博客网 时间:2024/06/06 01:26

源于对一个项目的bug,调试,一直出现的问题就是,在本地运行没有问题,但是,一旦上线,就会出现问题,同样相似的在下面的例子里面也出现这样的情况。

代码:

def foo(bar=[]):    bar.append('abc')    return barif __name__ == '__main__':    print foo()

在linux下,运行

[root@kvm_10_112_117_88 /data/flyfly]# python param.py
[‘abc’]
[root@kvm_10_112_117_88 /data/flyfly]# python param.py
[‘abc’]
[root@kvm_10_112_117_88 /data/flyfly]# python param.py
[‘abc’]
[root@kvm_10_112_117_88 /data/flyfly]# python param.py
[‘abc’]

都没有问题,
然而,在Python解释器中

>>> def foo(bar=[]):...     bar.append('abc')...     return bar...

运行

>>> foo()['abc']>>> foo()['abc', 'abc']>>> foo()['abc', 'abc', 'abc']

完全不能忍呀
这是为啥呢

先看看 Python中的默认参数是如何实现的,或者说,对于一个可变变量作为默认参数时,会发生什么

Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call.

在这篇文章https://segmentfault.com/a/1190000000743526中有详细讲到这个问题,也就是默认参数一次执行多次调用

为了研究Python中默认参数的运行机制,利用下面的代码进行测试
首先

def a():    print "a executed"    return []def b(x=a()):    print "id(x): ", id(x)    x.append(5)    print "x: ", x

运行结果

a executed

也就是在定义函数时,默认函数被复制,被执行,
增加如下代码

def a():    print "a executed"    return []def b(x=a()):    print "id(x): ", id(x)    x.append(5)    print "x: ", xfor i in range(2):    print "-" * 15, "Call b()", "-" * 15    b()    print b.__defaults__    print "id(b.__defaults__[0]): ", id(b.__defaults__[0])

运行结果

a executed
————— Call b() —————
id(x): 14226712
x: [5]
([5],)
id(b.defaults[0]): 14226712
————— Call b() —————
id(x): 14226712
x: [5, 5]
([5, 5],)
id(b.defaults[0]): 14226712

这里面看到,虽然多次调用b()函数,但是并不是每次都初始化里面的默认参数,两者使用的是同一个地址

修改代码

def a():    print "a executed"    return []def b(x=a()):    print "id(x): ", id(x)    x.append(5)    print "x: ", xfor i in range(2):    print "-" * 15, "Call b(list())", "-" * 15    b(list())    print b.__defaults__    print "id(b.__defaults__[0]): ", id(b.__defaults__[0])

结果

a executed
————— Call b(list()) —————
id(x): 34693920
x: [5]
([],)
id(b.defaults[0]): 34620696
————— Call b(list()) —————
id(x): 34693992
x: [5]
([],)
id(b.defaults[0]): 34620696

这里面每次都重新定义了一个list,所以不会是相同的地址

所以如果默认参数是一个可变变量,这时就会出现问题,
对于本文一开始出现的现象,每次运行Python之后其生命周期就会结束,而在Python解释器中,其生命周期会一直保持,所以才会出现这样的情况。

0 0
原创粉丝点击