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 fileinput模块使用介绍
Nov 30 Python
探究Python中isalnum()方法的使用
May 18 Python
利用Tkinter(python3.6)实现一个简单计算器
Dec 21 Python
Python中的Numpy矩阵操作
Aug 12 Python
使用Python OpenCV为CNN增加图像样本的实现
Jun 10 Python
pandas基于时间序列的固定时间间隔求均值的方法
Jul 04 Python
python中有关时间日期格式转换问题
Dec 25 Python
matplotlib制作雷达图报错ValueError的实现
Jan 05 Python
如何使用Python进行PDF图片识别OCR
Jan 22 Python
python3判断IP地址的方法
Mar 04 Python
Python中异常处理用法
Nov 27 Python
使用python创建股票的时间序列可视化分析
Mar 03 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
php在页面中调用fckeditor编辑器的方法
2011/06/10 PHP
基于PHP静态类的原罪详解
2013/05/06 PHP
ThinkPHP文件上传实例教程
2014/08/22 PHP
PHP实现对xml进行简单的增删改查(CRUD)操作示例
2017/05/19 PHP
js 学习笔记(三)
2009/12/29 Javascript
javascript动态加载二
2012/08/22 Javascript
JQuery实现表格动态增加行并对新行添加事件
2014/07/30 Javascript
IE6-IE9使用JSON、table.innerHTML所引发的问题
2015/12/22 Javascript
BootStrop前端框架入门教程详解
2016/12/25 Javascript
深入理解Node.js中的进程管理
2017/03/13 Javascript
推荐三款日期选择插件(My97DatePicker、jquery.datepicker、Mobiscroll)
2017/04/21 jQuery
WebGL学习教程之Three.js学习笔记(第一篇)
2019/04/25 Javascript
微信小程序实现下拉刷新动画
2019/06/21 Javascript
详解Vue中的基本语法和常用指令
2019/07/23 Javascript
简单分析js中的this的原理
2019/08/31 Javascript
[49:27]2018DOTA2亚洲邀请赛 4.4 淘汰赛 TNC vs VG 第一场
2018/04/05 DOTA
基于ID3决策树算法的实现(Python版)
2017/05/31 Python
Python+tkinter使用80行代码实现一个计算器实例
2018/01/16 Python
python爬虫爬取淘宝商品信息(selenum+phontomjs)
2018/02/24 Python
python+pyqt5实现图片批量缩放工具
2019/03/18 Python
python3常用的数据清洗方法(小结)
2019/10/31 Python
win7上tensorflow2.2.0安装成功 引用DLL load failed时找不到指定模块 tensorflow has no attribute xxx 解决方法
2020/05/20 Python
Python常驻任务实现接收外界参数代码解析
2020/07/21 Python
Ever New加拿大官网:彰显女性美
2018/10/05 全球购物
市场营销专科应届生求职信
2013/11/24 职场文书
应届大学毕业生找工作的求职信范文
2013/11/29 职场文书
4s客服专员岗位职责
2013/12/01 职场文书
大学校务公开实施方案
2014/03/31 职场文书
司法局2014法制宣传日活动总结
2014/11/01 职场文书
市场营销计划书范文
2015/01/16 职场文书
送给客户微信问候语!
2019/07/04 职场文书
2019年共青团工作条例最新版
2019/11/12 职场文书
Ajax请求超时与网络异常处理图文详解
2021/05/23 Javascript
pytorch 实现多个Dataloader同时训练
2021/05/29 Python
修改并编译golang源码的操作步骤
2021/07/25 Golang
5人制售《绝地求生》游戏外挂获利500多万元 被判刑
2022/03/31 其他游戏