Python中设置变量作为默认值时容易遇到的错误


Posted in Python onApril 03, 2015

思考一下下面的代码片段:
 

def foo(numbers=[]):
  numbers.append(9)
  print numbers

在这里,我们定义了一个 list (默认为空),给它加入9并且打印出来。
 

>>> foo()
[9]
>>> foo(numbers=[1,2])
[1, 2, 9]
>>> foo(numbers=[1,2,3])
[1, 2, 3, 9]

看起来还行吧?可是当我们不输入number 参数来调用 foo 函数时,神奇的事情发生了:
 

>>> foo() # first time, like before
[9]
>>> foo() # second time
[9, 9]
>>> foo() # third time...
[9, 9, 9]
>>> foo() # WHAT IS THIS BLACK MAGIC?!
[9, 9, 9, 9]

那么,这是神马情况?直觉告诉我们无论我们不输入 number 参数调用 foo 函数多少次,这里的9应该被分配进了一个空的 list。这是错的!在Python里,函数的默认值实在函数定义的时候实例化的,而不是在调用的时候。

那么我们仍然会问,为什么在调用函数的时候这个默认值却被赋予了不同的值?因为在你每次给函数指定一个默认值的时候,Python都会存储这个值。如果在调用函数的时候重写了默认值,那么这个存储的值就不会被使用。当你不重写默认值的时候,那么Python就会让默认值引用存储的值(这个例子里的numbers)。它并不是将存储的值拷贝来为这个变量赋值。这个概念可能对初学者来说,理解起来会比较吃力,所以可以这样来理解:有两个变量,一个是内部的,一个是当前运行时的变量。现实就是我们有两个变量来用相同的值进行交互,所以一旦 numbers 的值发生变化,也会改变Python里面保存的初始值的记录。

那么解决方案如下:
 

def foo(numbers=None):
  if numbers is None:
    numbers = []
  numbers.append(9)
  print numbers

通常,当人们听到这里,大家会问另一个关于默认值的问题。思考下面的程序:
 

def foo(count=0):
  count += 1
  print count

当我们运行它的时候,其结果完全是我们期望的:
 

>>> foo()
1
>>> foo()
1
>>> foo(2)
3
>>> foo(3)
4
>>> foo()
1

这又是为啥呢?其秘密不在与默认值被赋值的时候,而是这个默认值本身。整型是一种不可变的变量。跟 list 类型不同,在函数执行的过程中,整型变量是不能被改变的。当我们执行 count+=1 这句话时,我们并没有改变 count 这个变量原有的值。而是让 count 指向了不同的值。可是,当我们执行 numbers.append(9) 的时候,我们改变了原有的 list 。因而导致了这种结果。

下面是在函数里使用默认值时会碰到的另一种相同问题:
 

def print_now(now=time.time()):
  print now

跟前面一样,time.time() 的值是可变的,那么它只会在函数定义的时候计算,所以无论调用多少次,都会返回相同的时间 — 这里输出的时间是程序被Python解释运行的时间。

>>> print_now()
1373121487.91
>>> print_now()
1373121487.91
>>> print_now()
1373121487.91

* 这个问题和它的解决方案在 Python 2.x 和 3.x 里都是类似的,在Python 3.x 里面唯一的不同,是里面的print 表达式应该是函数调用的方式(print(numbers))。

Python 相关文章推荐
Python中getattr函数和hasattr函数作用详解
Jun 14 Python
Python检测生僻字的实现方法
Oct 23 Python
python bottle框架支持jquery ajax的RESTful风格的PUT和DELETE方法
May 24 Python
Python基于递归算法求最小公倍数和最大公约数示例
Jul 27 Python
Pandas DataFrame 取一行数据会得到Series的方法
Nov 10 Python
Python3爬虫使用Fidder实现APP爬取示例
Nov 27 Python
Python K最近邻从原理到实现的方法
Aug 15 Python
Python操作SQLite数据库过程解析
Sep 02 Python
Python 实现Image和Ndarray互相转换
Feb 19 Python
python 绘制国旗的示例
Sep 27 Python
详解Python利用configparser对配置文件进行读写操作
Nov 03 Python
python实现代码审查自动回复消息
Feb 01 Python
用Python编写一个简单的Lisp解释器的教程
Apr 03 #Python
举例讲解Python中is和id的用法
Apr 03 #Python
详解Python2.x中对Unicode编码的使用
Apr 03 #Python
对于Python中线程问题的简单讲解
Apr 03 #Python
python BeautifulSoup设置页面编码的方法
Apr 03 #Python
用Python编写一个简单的FUSE文件系统的教程
Apr 02 #Python
用Python中的__slots__缓存资源以节省内存开销的方法
Apr 02 #Python
You might like
php自动适应范围的分页代码
2008/08/05 PHP
Yii+MYSQL锁表防止并发情况下重复数据的方法
2016/07/14 PHP
php实现在新浪云中使用imagick生成缩略图并上传的方法
2016/09/26 PHP
PHP中的函数声明与使用详解
2017/05/27 PHP
PHP实现简单的模板引擎功能示例
2017/09/02 PHP
Some tips of wmi scripting in jscript (1)
2007/04/03 Javascript
javascript 常用方法总结
2009/06/03 Javascript
JavaScript中通过闭包解决只能取得包含函数中任何变量最后一个值的问题
2010/08/12 Javascript
B/S模式项目中常用的javascript汇总
2013/12/17 Javascript
JavaScript制作简易的微信打飞机
2015/03/31 Javascript
javascript巧用eval函数组装表单输入项为json对象的方法
2015/11/25 Javascript
ros::spin() 和 ros::spinOnce()函数的区别及详解
2016/10/01 Javascript
Node.JS中事件轮询(Event Loop)的解析
2017/02/25 Javascript
详解webpack模块化管理和打包工具
2018/04/21 Javascript
Angular5中调用第三方库及jQuery的添加的方法
2018/06/07 jQuery
JavaScript基于对象方法实现数组去重及排序操作示例
2018/07/10 Javascript
Vue 实现把表单form数据 转化成json格式的数据
2019/10/29 Javascript
JS document内容及样式操作完整示例
2020/01/14 Javascript
浅析Vue 中的 render 函数
2020/02/28 Javascript
vue计算属性+vue中class与style绑定(推荐)
2020/03/30 Javascript
vue2.0实现列表数据增加和删除
2020/06/17 Javascript
Angular+Ionic使用queryParams实现跳转页传值的方法
2020/09/05 Javascript
vue 导出文件,携带请求头token操作
2020/09/10 Javascript
简单谈谈offsetleft、offsetTop和offsetParent
2020/12/04 Javascript
[01:14]DOTA2亚洲邀请赛 ShowOpen
2015/02/07 DOTA
Python文件右键找不到IDLE打开项解决办法
2015/06/08 Python
详解Python的collections模块中的deque双端队列结构
2016/07/07 Python
Python+tkinter模拟“记住我”自动登录实例代码
2018/01/16 Python
用pandas按列合并两个文件的实例
2018/04/12 Python
python实现寻找最长回文子序列的方法
2018/06/02 Python
浅谈Python爬虫基本套路
2019/03/25 Python
python脚本调用iftop 统计业务应用流量的思路详解
2019/10/11 Python
Python通过fnmatch模块实现文件名匹配
2020/09/30 Python
日本食品网上商店:JaponShop.com
2017/11/28 全球购物
会计专业大学生求职信范文
2014/01/28 职场文书
MySQL 百万级数据的4种查询优化方式
2021/06/07 MySQL