python 默认参数问题的陷阱


Posted in Python onFebruary 29, 2016

python 里面一个常见的陷阱就是函数的默认参数问题。如下:

def func(mylist = []):
  mylist.append(1)
  return mylist

以下的执行结果如下:

print func()
print func()
print func()
print func(['a'])
print func()

结果如下:

[1]
[1, 1]
[1, 1, 1]
['a', 1]
[1, 1, 1, 1]

如此结果, 前面三个可以看出 如果没有指定参数的话, 每次调用函数时候, 调用的mylist 是同一个对象。这是因为函数的默认参数,是在代码编译成PyCodeObject的时候, 就已经创建了对象指针,并且存在该函数的func_default内。 以后在代码运行,调用函数的时候,如果没有指定参数的话, 每次调用的话, 该参数变量都是代码编译阶段的变量指针所指定的对象。

print func.func_default

此时结果就是:

([1, 1, 1, 1], )
默认参数分为两种情况:

默认参数值是不可变对象
此时函数的 func_default 一直指向该不变对象, 如果函数内部修改了该变量, 那么该默认参数会指向一个新的不可变对象.
不过func_default 不变。 而每次调用函数都是读取func_default, 因此每次执行都一样。

In [30]: def func2(var = 1):
  ....:   var += 1
  ....:   return var
  ....: 

In [31]: func2()
Out[31]: 2

In [32]: func2()
Out[32]: 2

In [34]: func2.func_defaults
Out[34]: (1,)

默认参数是可变对象,比如 list, dict, class等
这种情况下,如果在函数内修改了指针所指的对象(并未创建新的对象), 那么 func_default 就会改变。这正是开始的mylist发生变化的原因。看下面的例子,:

In [35]: def func(mylist = []):
  ....:   mylist = []  #这里 创建了新的对象,
       mylist.append(1)
       return mylist

In [44]: func()
Out[44]: [1]

In [45]: func.func_defaults
Out[45]: ([],)

由于创建了对象, mylist 只是作为一个 新建对象的别名存在, 后面在修改已经与 func_default 无关了。 
默认参数的一个应用

先看下面的一个经典的例子:

def outer():
  res = []
  for i in range(4):
    def inner(j):
      return j * i
    res.append(inner)
  return res

print [m(2) for m in outer()]

#简略版本:

def multipliers():
  return [lambda x : i * x for i in range(4)]
print [m(2) for m in multipliers()]

结果是 [6, 6, 6, 6] , 而不是 [0, 2, 4, 6], 原因就是闭包的延迟绑定。另外函数绑定的是变量而不是绑定数值。当循环结束了,i的值已经是3, 此时结果都是6. 一个解决方法便是,使用默认参数绑定数值。如下改动:

def outer():
  res = []
  for i in range(4):
    def inner(j, i = i):
      return j * i
    res.append(inner)
  return res

print [m(2) for m in outer()]

#简略版本:

def multipliers():
  return [lambda x, i = i : i * x for i in range(4)]
print [m(2) for m in multipliers()]

这样的话, 利用默认参数在代码编译的时候,便把参数写到函数的func_default中, 就可以绑定0,1,2,3了。结果自然就是

[0, 2, 4, 6]
这就是默认参数的一个应用。

上述还有一个生成器修改的方式

def multipliers():
  return (lambda x, i = i : i * x for i in range(4)) #修改成生成器
print [m(2) for m in multipliers()]
Python 相关文章推荐
在Python的web框架中编写创建日志的程序的教程
Apr 30 Python
Python Paramiko模块的安装与使用详解
Nov 18 Python
python日志记录模块实例及改进
Feb 12 Python
Python之web模板应用
Dec 26 Python
python2 与python3的print区别小结
Jan 16 Python
python简单商城购物车实例代码
Mar 15 Python
对Python3.6 IDLE常用快捷键介绍
Jul 16 Python
Python通过for循环理解迭代器和生成器实例详解
Feb 16 Python
Python流程控制 if else实现解析
Sep 02 Python
Python3 把一个列表按指定数目分成多个列表的方式
Dec 25 Python
详解Python的三种拷贝方式
Feb 11 Python
利用Python如何画一颗心、小人发射爱心
Feb 21 Python
简要讲解Python编程中线程的创建与锁的使用
Feb 28 #Python
Python中time模块和datetime模块的用法示例
Feb 28 #Python
python 写的一个爬虫程序源码
Feb 28 #Python
Python基础语法(Python基础知识点)
Feb 28 #Python
python中map()与zip()操作方法
Feb 27 #Python
python中input()与raw_input()的区别分析
Feb 27 #Python
python PIL模块与随机生成中文验证码
Feb 27 #Python
You might like
分享8个最佳的代码片段在线测试网站
2013/06/29 PHP
php写入、删除与复制文件的方法
2015/06/20 PHP
Yii2 中实现单点登录的方法
2018/03/09 PHP
baidu博客的编辑友情链接的新的层窗口!经典~支持【FF】
2007/02/09 Javascript
javascript 日历提醒系统( 兼容所有浏览器 )
2009/04/07 Javascript
js 格式化时间日期函数小结
2010/03/20 Javascript
JS中eval函数的使用示例
2013/07/21 Javascript
JS倒计时代码汇总
2014/11/25 Javascript
提升jQuery的性能需要做好七件事
2016/01/11 Javascript
Extjs实现下拉菜单效果
2016/04/01 Javascript
第九篇Bootstrap导航菜单创建步骤详解
2016/06/21 Javascript
JS如何设置cookie有效期为当天24点并弹出欢迎登陆界面
2016/08/04 Javascript
JS检测数组类型的方法小结
2017/03/14 Javascript
Textarea输入字数限制实例(兼容iOS&安卓)
2017/07/06 Javascript
webpack4 css打包压缩问题的解决
2018/05/18 Javascript
详解微信小程序用定时器实现倒计时效果
2019/04/30 Javascript
微信小程序云函数添加数据到数据库的方法
2020/03/04 Javascript
Vue实现开关按钮拖拽效果
2020/09/22 Javascript
Python中函数的用法实例教程
2014/09/08 Python
python打开网页和暂停实例
2014/09/30 Python
编写Python CGI脚本的教程
2015/06/29 Python
Python基于Flask框架配置依赖包信息的项目迁移部署
2018/03/02 Python
vue.js刷新当前页面的实例讲解
2020/12/29 Python
Sephora丝芙兰菲律宾官方网站:购买化妆品和护肤品
2017/04/05 全球购物
Ibood荷兰:互联网每日最佳在线优惠
2019/02/28 全球购物
Clarks西班牙官方在线商店:clarks鞋
2019/05/03 全球购物
澳大利亚领先的男装零售连锁店:Lowes
2020/08/07 全球购物
毕业生自我推荐
2013/11/04 职场文书
市场营销个人求职信范文
2014/02/02 职场文书
大学生职业生涯规划书参考模板
2014/03/05 职场文书
《和田的维吾尔》教学反思
2014/04/14 职场文书
陕西导游词
2015/02/04 职场文书
4S店客服专员岗位职责
2015/04/07 职场文书
2015个人年度工作总结范文
2015/05/28 职场文书
小学见习报告
2015/06/23 职场文书
使用golang编写一个并发工作队列
2021/05/08 Golang