Python 函数参数的默认值为可变对象时需要小心

WBOY
发布: 2023-04-22 13:37:07
转载
1411人浏览过

看到了有给 Python 函数参数的默认值传递可变对象,以此来加快斐波那契函数的递归速度,代码如下:

def fib(n, cache={0: 0, 1: 1}):
if n not in cache:
cache[n] = fib(n - 1) + fib(n - 2)
return cache[n]
登录后复制

是不是很新奇,居然可以这样,速度真的非常快,运行结果如下:

小心此坑:Python 函数参数的默认值是可变对象

不过,我劝你不要这样做,而且 IDE 也会提示你这样做很不好:

小心此坑:Python 函数参数的默认值是可变对象

这是因为,万物皆对象,Python 函数也是对象,参数的默认值就是对象的属性,在编译阶段参数的默认值就已经绑定到该函数,如果是可变对象,Python 函数参数的默认值在会被存储,并被所有的调用者共享,也就是说,一个函数的参数默认值如果是一个可变对象,例如 List、Dict,调用者 A 修改了它,那么之后调用者 B 在调用的时候看到的就是 A 修改后的结果,这样的模式往往会产生意想不到的结果,比如上面 fib 的算法,但更多的是 bug。

可以看下这段简单的代码:

def func(n, li = []):
for i in range(n):
li.append(i)
print(l)

func(2) # [0,1]
func(3,l=[1,2]) # [1,2,0,1,2]
func(2) # [0,1]
登录后复制

你可以先估算一下这段代码的输出,如果和注释中的一样,那你就错了。正确的结果是:

[0, 1]
[1, 2, 0, 1, 2]
[0, 1, 0, 1]
登录后复制

你可能会觉得,最后一个 func(2) 怎么是这样,不急,我们 print(id(li)) 调试一下:

def func(n, li = []):
print(id(li))
for i in range(n):
li.append(i)
print(li)

func(2)
func(3,li=[1,2])
func(2)
登录后复制

结果如下:

140670243756736
[0, 1]
140670265684928
[1, 2, 0, 1, 2]
140670243756736
[0, 1, 0, 1]
登录后复制

有没有发现,第一个 func(2) 和第二个 func(2) 的 id 是一样的,说明它们用到的是 li 是同一个,这就参数的默认值是可变对象的逻辑,对于所有的调用者来讲,是共享的。

Python之模块学习 中文WORD版
Python之模块学习 中文WORD版

本文档主要讲述的是Python之模块学习;python是由一系列的模块组成的,每个模块就是一个py为后缀的文件,同时模块也是一个命名空间,从而避免了变量名称冲突的问题。模块我们就可以理解为lib库,如果需要使用某个模块中的函数或对象,则要导入这个模块才可以使用,除了系统默认的模块(内置函数)不需要导入外。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看

Python之模块学习 中文WORD版 2
查看详情 Python之模块学习 中文WORD版

如果要深入研究 Python 为什么这么设计,可以移步 http://cenalulu.github.io/python/default-mutable-arguments/

如何避免?

最好的方式是不要使用可变对象作为函数默认值。如果非要这么用的话,下面是一种解决方案:

def generate_new_list_with(my_list=None, element=None):
if my_list is None:
my_list = []
my_list.append(element)
return my_list
登录后复制

这样,如果 my_list 默认值永远都是 []。

最后

我想那个 fib 函数的实现可能会让你印象深刻,不过请注意,这样的用法非常危险,不可用于自己的代码中。

以上就是Python 函数参数的默认值为可变对象时需要小心的详细内容,更多请关注php中文网其它相关文章!

相关标签:
python速学教程(入门到精通)
python速学教程(入门到精通)

python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
来源:51CTO.COM网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号