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通过函数属性实现全局变量的方法
May 16 Python
在Linux系统上安装Python的Scrapy框架的教程
Jun 11 Python
Python的多态性实例分析
Jul 07 Python
git进行版本控制心得详谈
Dec 10 Python
python实现雨滴下落到地面效果
Jun 21 Python
Python中的取模运算方法
Nov 10 Python
Python实现查找数组中任意第k大的数字算法示例
Jan 23 Python
python实现把二维列表变为一维列表的方法分析
Oct 08 Python
利用django创建一个简易的博客网站的示例
Sep 29 Python
用Python进行websocket接口测试
Oct 16 Python
Pandas直接读取sql脚本的方法
Jan 21 Python
Python基本知识点总结
Apr 07 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执行linux系统命令的常用函数使用说明
2010/04/27 PHP
PHP 读取和编写 XML
2014/11/19 PHP
ThinkPHP模板标签eq if 中区分0,null,false的方法
2017/03/24 PHP
jquery 简单导航实现代码
2009/09/11 Javascript
javascript 判断数组是否已包含了某个元素的函数
2010/05/30 Javascript
javascript中有趣的反柯里化深入分析
2012/12/05 Javascript
JavaScript中的数值范围介绍
2014/12/29 Javascript
D3.js中data(), enter() 和 exit()的问题详解
2015/08/17 Javascript
全面解析Bootstrap图片轮播效果
2015/12/03 Javascript
由浅入深讲解Javascript继承机制与simple-inheritance源码分析
2015/12/13 Javascript
深入理解jQuery3.0的domManip函数
2016/09/01 Javascript
webpack+vue.js实现组件化详解
2016/10/12 Javascript
Node调用Java的示例代码
2017/09/20 Javascript
JS计算输出100元钱买100只鸡问题的解决方法
2018/01/04 Javascript
Vue前端开发规范整理(推荐)
2018/04/23 Javascript
vue-cli3.X快速创建项目的方法步骤
2019/11/14 Javascript
js 闭包深入理解与实例分析
2020/03/19 Javascript
Python读写unicode文件的方法
2015/07/10 Python
关于Python面向对象编程的知识点总结
2017/02/14 Python
python使用socket创建tcp服务器和客户端
2018/04/12 Python
python实现文件助手中查看微信撤回消息
2019/04/29 Python
Python3远程监控程序的实现方法
2019/07/15 Python
基于python使用tibco ems代码实例
2019/12/20 Python
Python socket连接中的粘包、精确传输问题实例分析
2020/03/24 Python
Python能做什么
2020/06/02 Python
浅析Python面向对象编程
2020/07/10 Python
浅析Python 序列化与反序列化
2020/08/05 Python
用pushplus+python监控亚马逊到货动态推送微信
2021/01/29 Python
传播学专业毕业生自荐信
2013/11/04 职场文书
党员活动日总结
2014/05/05 职场文书
一份文言文检讨书
2014/09/13 职场文书
印刷技术专业自荐信
2014/09/18 职场文书
2015年党日活动总结范文
2015/03/25 职场文书
2015年法制宣传月活动总结
2015/03/26 职场文书
《这片土地是神圣的》教学反思
2016/02/16 职场文书
年中了,该如何写好个人述职报告?
2019/07/02 职场文书