默认值的做用域python
def foo(xyz=[]): xyz.append(10) print(xyz) foo()#[10] foo()#[10, 10]
为何第二次调用foo函数打印的是[10, 10]???app
由于函数也是对象,python把函数的默认值放在了属性中,这个属性就伴随着这个函数对象的整个生命周期;ide
查看foo.__defaults__属性;函数
def foo(xyz=[], u='abc', z=123): xyz.append(1) return xyz print(foo(), id(foo))#[1] 12588984 print(foo.__defaults__)#([1], 'abc', 123) print(foo(), id(foo))#[1, 1] 12588984 print(foo.__defaults__)#([1, 1], 'abc', 123)
函数地址并无变,就是说函数这个对象的没有变,调用它,它的属性__defaults__中使用元组保存全部默认值;对象
xyz默认值是引用类型,引用类型的元素变更,并非元组的变化;生命周期
非引用类型的例子: def foo(w, u='abc', z=123): u = 'xyz' z = 789 print(w, u, z) print(foo.__defaults__)#('abc', 123) foo('magedu')#magedu xyz 789 print(foo.__defaults__)#('abc', 123)
属性__defaults__中使用元组保存全部默认值,它不会由于在函数体内使用了它而发生改变。
ci
可变类型默认值,若是使用默认值,就可能修改这个默认值;
作用域
有时候这个特性是好的,有的时候这种特性是很差的,有反作用;it
如何作到按需改变呢?看以下两种方法:class
def foo(xyz=[], u='abc', z=123): xyz = xyz[:]#影子拷贝 xyz.append(1) print(xyz) print(foo.__defaults__) foo() print(foo.__defaults__) foo() print(foo.__defaults__) foo([10]) print(foo.__defaults__) foo([10, 5]) print(foo.__defaults__)
函数体内,不改变默认值:
xyz都是传入参数或默认参数的副本,若是就想修改原参数,无能为力;
def foo(xyz=None, u='abc', z=123): if xyz is None: xyz = [] xyz.append(1) print(xyz) foo() print(foo.__defaults__) foo() print(foo.__defaults__) foo([10]) print(foo.__defaults__) foo([10, 5]) print(foo.__defaults__)
使用不可变类型默认值:
若是使用缺省值None就建立一个列表;
若是传入一个列表,就修改这个列表;
总结:
第一种方法,使用影子拷贝建立一个新的对象,永远不能改变传入的参数
第二种方法,
经过值的判断就能够灵活的选择建立或者修改传入对象;
这种方式灵活,应用普遍;
不少函数的定义,均可以看到使用None这个不可变的值做为默认参数,可说这是一种惯法。