有时,默认参数为空列表似乎很自然。然而,Python在这些情况下会产生意想不到的行为。

例如,我有一个函数:

def my_func(working_list=[]):
    working_list.append("a")
    print(working_list)

第一次调用它时,默认值将工作,但之后的调用将更新现有列表(每次调用一个“a”)并打印更新后的版本。

那么,python的方法是什么来获得我想要的行为(每次调用都有一个新的列表)?


当前回答

其他答案已经提供了要求的直接解决方案,然而,由于这是Python程序员新手的一个非常常见的陷阱,因此值得添加对Python为什么会这样做的解释,这在可变默认参数下的Python漫游指南中得到了很好的总结:

Python的默认实参在定义函数时只计算一次,而不是每次调用函数时都计算(就像Ruby中那样)。这意味着如果你使用一个可变的默认参数并改变了它,你将在以后所有对函数的调用中也改变了这个对象。

其他回答

def my_func(working_list=None):
    if working_list is None: 
        working_list = []

    # alternative:
    # working_list = [] if working_list is None else working_list

    working_list.append("a")
    print(working_list)

文档说你应该使用None作为默认值,并在函数体中显式地测试它。

引用自https://docs.python.org/3/reference/compound_stmts.html#function-definitions

Default parameter values are evaluated from left to right when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call. This is especially important to understand when a default parameter is a mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default value is in effect modified. This is generally not what was intended. A way around this is to use None as the default, and explicitly test for it in the body of the function, e.g.:

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin

也许最简单的事情就是在脚本中创建列表或元组的副本。这样就避免了检查的需要。例如,

    def my_funct(params, lst = []):
        liste = lst.copy()
         . . 

在这种情况下,这并不重要,但你可以使用对象标识来测试None:

if working_list is None: working_list = []

你也可以利用python中布尔运算符or的定义:

working_list = working_list or []

但是,如果调用者给你一个空列表(算作false)作为working_list,并期望你的函数修改他给它的列表,这将出乎意料。

其他答案已经提供了要求的直接解决方案,然而,由于这是Python程序员新手的一个非常常见的陷阱,因此值得添加对Python为什么会这样做的解释,这在可变默认参数下的Python漫游指南中得到了很好的总结:

Python的默认实参在定义函数时只计算一次,而不是每次调用函数时都计算(就像Ruby中那样)。这意味着如果你使用一个可变的默认参数并改变了它,你将在以后所有对函数的调用中也改变了这个对象。