社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

那些是python新手容易忽视的错误

python • 8 年前 • 556 次点击  

用一个可变的值作为默认值

这是一个绝对值得放在第一个来说的问题。不仅仅是因为产生这种BUG的原因很微妙,而且这种问题也很难检查出来。思考一下下面的代码片段:
                           Python学习交流 330637182 群内每天更新相关资料

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学习交流 330637182 群内每天更新相关资料

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

那么解决方案如下:

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 。因而导致了这种结果。
                        Python学习交流 330637182 群内每天更新相关资料

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

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))。

* 大家应该注意到我在解决方案里用了 if  numbers is None 而不是 if not numbers 。这是另一种常见的错误,我准备在接下来的文章里面介绍。


希望这篇文章能够对你现在或者之后的学习有所帮助,学习编程(python)并不难,各位可以加下群:330637182   (免费资料+视频)一起学习交流提升技术,你要知道当你成功之后,现在付出的努力都是值得的。 



今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/weixin/ciTNHjKPcJ
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/1978
 
556 次点击