Python中的默认参数值

Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发。

Python对默认参数值的处理方法是少有的几个易使大多数新手Python程序员犯错的地方之一。(通常只犯一次)


导致困惑的地方是当你使用“可变”对象作为(参数的)默认值时的(程序)行为。(可变)也就是说值可以原地修改,像列表或字典。


看下面的例子:

1.jpg


就像你看到的那样,列表变得越来越长。如果你查看列表的ID,你会发现函数实际上总是返回同一个对象。

2.jpg


原因很简单:函数在每次调用时总是使用同一个对象。我们做的修改行为有“粘性”。


为什么会这样?


属于函数定义的默认参数值当且仅当“def”语句执行时求值。请看:


http://docs.python.org/ref/function.html (死链接)


语言参考中的相关章节。


要注意Python中的“def”语句是可执行的,而且默认参数是在“def”语句的环境下求值的。如果“def”语句执行了多次,那么它每次将产生新的函数对象(对象会带着全新的默认值)。下面我们会看到这样的例子的。


那要怎么做?


迂回方法是,就像其他人已经提到了的,使用占位符值来替代默认值。None是一个常用的值:

3.jpg


如果你需要处理任意对象(包括None),你可以使用哨兵对象:

4.jpg


在很早以前,即在“object”对象引入之前,有时你会看到像下面这样的代码:

5.jpg


这个代码用于创建一个具有唯一ID的对象;这对中括号([])在每次执行时产生新的列表。


对可变默认参数的合法(合理)使用


最后,要提到很多高级的Python代码经常使用这个机制的好处。例如,假设你要在一个循环里创建了一堆UI按钮,而你可能会使用像下面这样的代码:

6.jpg


这样你会发现所有的回调函数都打印出相同的值(在这个情况下,很可能是9)。原因是Python的嵌套作用域是绑定到变量的,而不是绑定到对象值的。所以所有的回调函数实例将会看到当前(也是最后)的变量“i”的值。为了修正这个问题,使用下面的代码:

7.jpg


那个“i=i”的步伐将绑定参数“i”(一个局部变量)到当前的外部变量“i”的值。


两个其他的例子使用的是局部缓存:

8.jpg


(这对某些递归算法很好)


另一个例子,对应高度优化的代码,对全局名字的局部重新绑定:

9.jpg


详细来说,这是怎么工作的?


当Python执行“def”语句时,它使用一些已有的东西(包括编译了的函数体的代码和当前的名字空间),然后创建出一个新的函数对象。当它做这个的时候,默认值也会被求值。


这些各种各样的组件也能作为函数对象的属性而访问。使用我们先前定义过的函数:

10.jpg


由于你可以访问它们,因而你也可以修改它们:

11.jpg


当然,这可不是我推荐的正常使用方法。


另一个重置默认值的方法就是简单的重新执行一下那个相同的“def”语句。Python会重新创建一个新的到这个代码对象绑定,重新计算默认值,然后将这个函数对象赋值给同以前一样的那个变量。但是要着重指出,请在你确切知道你在做什么的时候才能这么做。


最后,如果你刚好有函数各个部分,而不是函数本身,你可以使用new模块中的function类来创建你自己的函数对象。



英文原文:http://effbot.org/zone/default-values.htm
译者:yuezy3
 

2月15日11:00到13:00网站停机维护,13:00前恢复
iPy智能助手 双击展开
查看更多聊天记录
(Ctrl+回车)换行