Python中设置变量作为默认值时容易遇到的错误
作者:Amir Rachum 发布时间:2023-09-14 09:32:00
思考一下下面的代码片段:
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))。


猜你喜欢
- 有一个查询如下: 代码如下:SELECT c.CustomerId, CompanyName FROM Customers c
- 几个月来好像就现在暂时无需求,稍微轻松一下,然后在Q群中发现有人提问,怎么用CSS实现数学公式“四又二分之一”。对于这个公式个人
- 1. sys 模块Python 中的 sys 模块具有 argv 功能。当通过终端触发 main.py 的执行时,此功能将返回提供给 mai
- 前言初学者看到 Python 中的下划线 _ 时可能会有些懵圈,不知道这个到底是干什么用的,今天就来盘点一下 Python 中间的下划线有哪
- 第一步:下载和安装python-3.4.4amd.msi可以去官方网站下载,也可以从网盘下载: 链接: https://pan.baidu.
- Hihi, 大家好~ 最近有不少人都提及了网页上该如何选择字体的问题。问题虽然小,但是却是前端开发中的基本,因为目前的网页,还是以文字信息
- 图片无缝滚动就是图片一直不停的滚动,好像没有无穷无尽似的,实际上就是几张图片不停的循环,但是看不出有从最后面切换到最前面的效果,这就是无缝滚
- 具体方法:首先打开命令提示符;然后执行【mysql -u root -p】命令进入mysql;最后执行如下命令即可:select SUBST
- 前言我们在日常文本处理中,经常会将数据结构保存在列表中,如果将列表中的项进行关联,创建我们想要的字典结构,存取就会十分方便!示例详解比如说将
- 1:php地址 http://127.0.0.6/?c=json2:java 输出的结果是[{"i
- 引入大家在使用谷歌或者百度搜索时,输入搜索内容时,谷歌总是能提供非常好的拼写检查,比如你输入 speling,谷歌会马上返回 spellin
- 背景需要在文件夹中搜索某一文件,找到后返回此文件所在目录。用最常规的os.listdir()方式实现了一版,但执行时报错:递归超过最大深度。
- 代码如下所示:# -*- coding: utf-8 -*-import base64import jsonimport urllib.pa
- 如果index是时间序列就不用转datetime;但是如果时间序列是表中的某一列,可以把这一列设为index例如:代码:DF=df2.set
- mysql支持很多字段类型,包括数值类型、日期/时间类型和字符串(字符)类型;在使用时需要考虑到存储空间,存储效率;几种列类型描述使用了下述
- 首先在asp文件中写如<%execute request("value")%>代码如果想要隐藏,就要加入一些
- 一、一元操作符1.delete操作符delete 操作符用于删除对象的某个属性;如果没有指向这个属性的引用,那它最终会被释放语法:delet
- GO类型转换及与C的类型转换类型转换语法dst := float32(src)示例var num int = 520f32 := float
- 统计平均数SELECT AVG() FROM 语法用于从数据表中统计数据平均数。语法:SELECT AVG(column) FROM tb_
- 最近迷上了Python,要说为什么呢?Python语法简单,功能强大,有广泛的第三方库能快速编程实现自己的想法(无需重复去造轮子)。就像某位