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

例如,如果我有一个函数:

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

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

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

有帮助吗?

解决方案

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

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

说,你应该使用None默认和明确的文档测试的函数体的。

其他提示

如要求

现有的答案已经提供了直接的解决方案。然而,由于这是一个新的Python程序员很常见的陷阱,值得补充为什么蟒蛇的行为这样解释,这是很好的总结了“的漫游指南到Python ”为“可变默认参数“: http://docs.python-guide.org/en/latest/writing/陷阱/

报价:“ Python的默认参数进行评估,一旦被定义的功能时,不会在每次调用函数时(就像是在说,红宝石)这意味着,如果您使用的是可变的默认参数和变异它,你会和已经变异是对象的功能,未来所有的调用以及的“

样本的代码来实现它:

def foo(element, to=None):
    if to is None:
        to = []
    to.append(element)
    return to

这不是问题在这种情况下,但可以使用对象标识来测试无:

if working_list is None: working_list = []

您也可以采取怎样的布尔运算符的优点或在Python定义:

working_list = working_list or []

虽然这将表现异常,如果来电者给你一个空列表(算作是假的)的working_list并期望你的函数来修改他给它的列表。

如果该函数的目的是 调整 参数传递为 working_list, ,请参阅 HenryR 的回答(=无,检查里面是否有“无”)。

但是,如果您不打算改变参数,只是将其用作列表的起点,则可以简单地复制它:

def myFunc(starting_list = []):
    starting_list = list(starting_list)
    starting_list.append("a")
    print starting_list

(或者在这个简单的例子中 print starting_list + ["a"] 但我想这只是一个玩具示例)

一般来说,改变你的参数在 Python 中是不好的风格。唯一完全期望改变对象的函数是对象的方法。改变可选参数的情况更加罕见——仅在某些调用中发生的副作用真的是最好的接口吗?

  • 如果您按照“输出参数”的 C 习惯来执行此操作,则完全没有必要 - 您始终可以将多个值作为元组返回。

  • 如果您这样做是为了有效地构建一长串结果而不构建中间列表,请考虑将其编写为生成器并使用 result_list.extend(myFunc()) 当你调用它的时候。这样你的调用约定就保持非常干净。

改变可选参数的一种模式 经常做的是递归函数中隐藏的“备忘录”参数:

def depth_first_walk_graph(graph, node, _visited=None):
    if _visited is None:
        _visited = set()  # create memo once in top-level call

    if node in _visited:
        return
    _visited.add(node)
    for neighbour in graph[node]:
        depth_first_walk_graph(graph, neighbour, _visited)

我可能是题外话,但要记住,如果你只是想传递一个可变数量的参数,在Python的方式是通过一个元组*args或字典**kargs。这些都是可选的,并且比语法myFunc([1, 2, 3])更好。

如果你想传递一个元组:

def myFunc(arg1, *args):
  print args
  w = []
  w += args
  print w
>>>myFunc(1, 2, 3, 4, 5, 6, 7)
(2, 3, 4, 5, 6, 7)
[2, 3, 4, 5, 6, 7]

如果你想传递的字典:

def myFunc(arg1, **kargs):
   print kargs
>>>myFunc(1, option1=2, option2=3)
{'option2' : 2, 'option1' : 3}

有已经好和正确答案提供。我只是想给另一种语法来写你想做的事,我觉得更漂亮时,你比如想创建一个默认的空列表类的内容:

class Node(object):
    def __init__(self, _id, val, parents=None, children=None):
        self.id = _id
        self.val = val
        self.parents = parents if parents is not None else []
        self.children = children if children is not None else []

此片断利用了否则如果操作者语法。我喜欢它,尤其是因为它是一个整洁的小的一行没有冒号等方式参与,它几乎读起来就像一个正常的英语句子。 :)

在你的情况,你可以写

def myFunc(working_list=None):
    working_list = [] if working_list is None else working_list
    working_list.append("a")
    print working_list

我把UCSC扩展类Python for programmer

哪些是真正的:DEF FN(数据= []):

  

a)是一个好主意,让您的数据列表开始空的,每一个电话。

     

b)是一个好主意,以便对函数的所有调用,不提供任何通话参数将获得空列表的数据。

     

c)是一个合理的想法,只要你的数据是字符串的列表。

     

d)是一个好主意,因为默认[]将累积数据和默认[]将与后续调用改变。

答案:

  

d)是一个好主意,因为默认[]将累积数据和默认[]将与后续调用改变。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top