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基于multiprocessing的多进程创建方法
Jun 04 Python
Python下的常用下载安装工具pip的安装方法
Nov 13 Python
python字符串str和字节数组相互转化方法
Mar 18 Python
Mac中升级Python2.7到Python3.5步骤详解
Apr 27 Python
Python实现简单网页图片抓取完整代码实例
Dec 15 Python
python re模块findall()函数实例解析
Jan 19 Python
详解Django项目中模板标签及模板的继承与引用(网站中快速布置广告)
Mar 27 Python
python实现Excel文件转换为TXT文件
Apr 28 Python
python调用私有属性的方法总结
Jul 24 Python
Python批量修改xml的坐标值全部转为整数的实例代码
Nov 26 Python
Django视图类型总结
Feb 17 Python
python 利用 PIL 将数组值转成图片的实现
Apr 12 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
不用数据库的多用户文件自由上传投票系统(2)
2006/10/09 PHP
php下通过curl抓取yahoo boss 搜索结果的实现代码
2011/06/10 PHP
在Windows XP下安装Apache+MySQL+PHP环境
2015/02/22 PHP
在Mac OS上自行编译安装Apache服务器和PHP解释器
2015/12/24 PHP
Laravel框架查询构造器 CURD操作示例
2019/09/04 PHP
详解laravel passport OAuth2.0的4种模式
2019/11/04 PHP
js tab 选项卡
2009/04/26 Javascript
jquery中的查找parents与closest方法之间的区别
2013/12/02 Javascript
JavaScript判断变量是否为空的自定义函数分享
2015/01/31 Javascript
JS表格组件神器bootstrap table详解(强化版)
2016/05/26 Javascript
详谈jQuery Ajax(load,post,get,ajax)的用法
2017/03/02 Javascript
JS动态修改网页body的背景色实例代码
2017/10/07 Javascript
实例分析JS中的相等性判断===、 ==和Object.is()
2019/11/17 Javascript
vue radio单选框,获取当前项(每一项)的value值操作
2020/09/10 Javascript
[07:03]显微镜下的DOTA2第九期——430圣堂刺客杀戮秀
2014/06/20 DOTA
[54:51]Ti4 冒泡赛第二轮LGD vs C9 3
2014/07/14 DOTA
Python中实现常量(Const)功能
2015/01/28 Python
基于wxpython开发的简单gui计算器实例
2015/05/30 Python
详解如何使用Python编写vim插件
2017/11/28 Python
PyQT实现菜单中的复制,全选和清空的功能的方法
2019/06/17 Python
如何在Cloud Studio上执行Python代码?
2019/08/09 Python
Python3.6实现根据电影名称(支持电视剧名称),获取下载链接的方法
2019/08/26 Python
使用python-cv2实现Harr+Adaboost人脸识别的示例
2020/10/27 Python
Python中pass语句的作用是什么
2016/06/01 面试题
党的群众路线教育实践活动心得体会
2014/03/03 职场文书
贷款担保申请书
2014/05/20 职场文书
销售目标责任书
2014/07/23 职场文书
2014旅游局党组书记党建工作汇报材料
2014/11/02 职场文书
机动车交通事故协议书
2015/01/29 职场文书
酒店辞职书范文
2015/02/26 职场文书
看雷锋电影观后感
2015/06/10 职场文书
公司车队管理制度
2015/08/04 职场文书
幼儿园安全管理制度
2015/08/05 职场文书
Python 如何将integer转化为罗马数(3999以内)
2021/06/05 Python
python脚本框架webpy模板控制结构
2021/11/20 Python
Python中的socket网络模块介绍
2022/07/23 Python