Python’s handling of default parameter values is one of a few things that tends to trip up most new Python programmers (but usually only once).

What causes the confusion is the behaviour you get when you use a “mutable” object as a default value; that is, a value that can be modified in place, like a list or a dictionary.

An example:

>>> def function(data=[]):
... data.append(1)
... return data
...
>>> function()
[1]
>>> function()
[1, 1]
>>> function()
[1, 1, 1]

As you can see, the list keeps getting longer and longer. If you look at the list identity, you’ll see that the function keeps returning the same object:

>>> id(function())
12516768
>>> id(function())
12516768
>>> id(function())
12516768

The reason is simple: the function keeps using the same object, in each call. The modifications we make are “sticky”.

Why does this happen? #

Default parameter values are always evaluated when, and only when, the “def” statement they belong to is executed; see:

http://docs.python.org/ref/function.html (dead link)

for the relevant section in the Language Reference.

Also note that “def” is an executable statement in Python, and that default arguments are evaluated in the “def” statement’s environment. If you execute “def” multiple times, it’ll create a new function object (with freshly calculated default values) each time. We’ll see examples of this below.

What to do instead? #

The workaround is, as others have mentioned, to use a placeholder value instead of modifying the default value. None is a common value:

def myfunc(value=None):
if value is None:
value = []
# modify value here

If you need to handle arbitrary objects (including None), you can use a sentinel object:

sentinel = object()

def myfunc(value=sentinel):
if value is sentinel:
value = expression
# use/modify value here

In older code, written before “object” was introduced, you sometimes see things like

sentinel = ['placeholder']

used to create a non-false object with a unique identity; [] creates a new list every time it is evaluated.

Valid uses for mutable defaults #

Finally, it should be noted that more advanced Python code often uses this mechanism to its advantage; for example, if you create a bunch of UI buttons in a loop, you might try something like:

for i in range(10):
def callback():
print "clicked button", i
UI.Button("button %s" % i, callback)

only to find that all callbacks print the same value (most likely 9, in this case). The reason for this is that Python’s nested scopes bind to variables, not object values, so all callback instances will see the current (=last) value of the “i” variable. To fix this, use explicit binding:

for i in range(10):
def callback(i=i):
print "clicked button", i
UI.Button("button %s" % i, callback)

The “i=i” part binds the parameter “i” (a local variable) to the current value of the outer variable “i”.

Two other uses are local caches/memoization; e.g.

(It happened to me in one of the first Python programs I ever wrote, and it took several years before we spotted the (non-critical) bug, when someone looked a bit more carefully at the contents of a property file, and wondered what all those things were doing there…)

def calculate(a, b, c, memo={}):
try:
value = memo[a, b, c] # return already calculated value
except KeyError:
value = heavy_calculation(a, b, c)
memo[a, b, c] = value # update the memo dictionary
return value

(this is especially nice for certain kinds of recursive algorithms)

and, for highly optimized code, local rebinding of global names:

import math

def this_one_must_be_fast(x, sin=math.sin, cos=math.cos):
...

How does this work, in detail? #

When Python executes a “def” statement, it takes some ready-made pieces (including the compiled code for the function body and the current namespace), and creates a new function object. When it does this, it also evaluates the default values.

The various components are available as attributes on the function object; using the function we used above:

>>> function.func_name
'function'
>>> function.func_code
<code object function at 00BEC770, file "<stdin>", line 1>
>>> function.func_defaults
([1, 1, 1],)
>>> function.func_globals
{'function': <function function at 0x00BF1C30>,
'__builtins__': <module '__builtin__' (built-in)>,
'__name__': '__main__', '__doc__': None}

Since you can access the defaults, you can also modify them:

>>> function.func_defaults[0][:] = []
>>> function()
[1]
>>> function.func_defaults
([1],)

However, this is not exactly something I’d recommend for regular use…

Another way to reset the defaults is to simply re-execute the same “def” statement. Python will then create a new binding to the code object, evaluate the defaults, and assign the function object to the same variable as before. But again, only do that if you know exactly what you’re doing.

And yes, if you happen to have the pieces but not the function, you can use thefunction class in the new module to create your own function object.

Default Parameter Values in Python的更多相关文章

  1. 《理解 ES6》阅读整理:函数(Functions)(一)Default Parameter Values

    对于任何语言来说,函数都是一个重要的组成部分.在ES6以前,从JavaScript被创建以来,函数一直没有大的改动,留下了一堆的问题和很微妙的行为,导致在JavaScript中使用函数时很容易出现错误 ...

  2. [Python] Pitfalls: About Default Parameter Values in Functions

    Today an interesting bug (pitfall) is found when I was trying debug someone's code. There is a funct ...

  3. python's default parameter

    [python's default parameter] 对于值类型(int.double)的default函数参数,函数不会保存对默认类型的修改.对于mutable objectd类型的默认参数,会 ...

  4. 除去Scala的糖衣(13) -- Default Parameter Value

    欢迎关注我的新博客地址:http://cuipengfei.me/ 好久没有写博客了,上一次更新竟然是一月份. 说工作忙都是借口,咋有空看美剧呢. 这半年荒废掉博客说到底就是懒,惯性的懒惰.写博客这事 ...

  5. More about Parameter Passing in Python(Mainly about list)

    我之前写了一篇关于Python参数传递(http://www.cnblogs.com/lxw0109/p/python_parameter_passing.html)的博客, 写完之后,我发现我在使用 ...

  6. JavaScript函数的默认参数(default parameter)

    JavaScript函数的默认参数(default parameter) js函数参数的默认值都是undefined, ES5里,不支持直接在形参里写默认值.所以,要设置默认值,就要检测参数是否为un ...

  7. How to: Initialize Business Objects with Default Property Values in XPO 如何:在 XPO 中用默认属性值初始化业务对象

    When designing business classes, a common task is to ensure that a newly created business object is ...

  8. How to: Initialize Business Objects with Default Property Values in Entity Framework 如何:在EF中用默认属性值初始化业务对象

    When designing business classes, a common task is to ensure that a newly created business object is ...

  9. Fixing Poor MySQL Default Configuration Values

    I've recently been accumulating some MySQL configuration variables that have defaults which have pro ...

随机推荐

  1. libsvm数据处理初略流程

  2. LINUX命令批量替换文件中的字符串

    sed -i "s/abcd/1234/g" `grep abcd -rl /home/data` find /data/web  -type f -exec  sed -i 's ...

  3. 解决Android中No resource found that matches android:TextAppearance.Material.Widget.Button.Inverse问题

    解决Android中No resource found that matches android:TextAppearance.Material.Widget.Button.Inverse问题http ...

  4. ExtJS基础知识总结:常用控件使用方式(一)

    概述 最近一直在做相关ExtJs方面的项目,遇到了ExtJs使用方面的一系列问题,现在将使用技巧做个记录汇总,以便于下次能够快速使用.以下都是ExtJs控件的常用方法,做简单汇总,俗话说,好记星不如烂 ...

  5. vmware中虚拟机与主机ping不通,桥接模式,IP地址在同一网段,无法互ping!

    现象描述:网卡选用的桥接模式,IP地址在同一个网段,虚拟机内部可以正常上网,但是Guest OS和Host OS无法互ping! 原因:虚拟机里的防火墙没有关闭,导致禁用ping功能. 解决方法:关闭 ...

  6. Android 笔记 文件存取 day5

    针对文件的存取 package com.example.file01; import com.example.service.FileService; import android.app.Activ ...

  7. java中的多线程

    什么是多线程? 首先得知道什么是线程? 线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行.也可以把它理解为代码运行的上下文.所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务. ...

  8. 【CentOS】LAMP

    文章需要整合,学习需要归纳,博主把一连四篇的LAMP合并成为一片长篇的大部头,并梳理了一下他们的关系,希望对各位有所帮助 最近一次更新:2016年12月21日21:38:31 本文为博主JerryCh ...

  9. android Studio 百度KEY获得发布版 SHA1 的方法

    看图说话 build-->Generate Signed APK... create new(看不懂单词意思的同胞可以参考这个网址http://www.cnblogs.com/why168888 ...

  10. OpenCV2.4.13+VS2013开发环境配置

    List1:完成 写在前面:之前电脑很杂乱的装了OpenCV的2个版本,在配置OpenCV和VS2013环境时死活配不好.但是接下来的工作要用到,没有办法,还是得好好做.今天重新装了OpenCV2.4 ...