Python 语法精炼1
Python 函数默认参数机制
默认参数的计算时机
-
默认参数在函数定义时计算一次,不是在函数调用时。
1
2
3def foo(x=[]):
x.append(1)
return x每次调用
foo(),都会操作同一个列表对象。
可变对象的陷阱
-
默认参数如果是 可变对象(如
list,dict,set),就会在多次调用中共享状态。1
2
3
4
5
6
7
8def add_item(item, bag=[]):
bag.append(item)
return bag
add_item('apple') # ['apple']
add_item('banana') # ['apple', 'banana']
add_item('cherry', []) # ['cherry']
add_item('date') # ['apple', 'banana', 'date'] -
因此,后续调用会“继承”前一次的内容。
安全写法
使用不可变对象(如 None)作为哨兵值,确保每次都新建对象:
1 | def add_item(item, bag=None): |
内部原理
-
Python 将默认参数保存在函数对象的
__defaults__属性中。1
2add_item.__defaults__
([],) -
因此,默认参数本质上是绑定在函数定义上的持久状态。
-
Python 的设计哲学之一:函数是对象,默认参数是函数对象的属性。
延伸思考
该机制在某些情况下可以刻意利用:
-
作为缓存(memoization)的一种简单实现。
1
2
3
4def fib(n, _cache={0:0, 1:1}):
if n not in _cache:
_cache[n] = fib(n-1) + fib(n-2)
return _cache[n]此时,可变默认参数的“持久性”反而是一个特性。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Telason!
