有时,使用默认参数(即空列表)似乎很自然.然而,Python在这些情况下会出现意外行为.
例如,我有一个功能:
def my_func(working_list = []): working_list.append("a") print(working_list)
第一次使用默认值调用它将起作用,但之后的调用将使用不断更新的列表.
那么,获得我想要的行为的pythonic方法是什么(每个调用都有一个新的列表)?
def my_func(working_list=None): if working_list is None: working_list = [] working_list.append("a") print(working_list)
我是怎么做到的.
现有的答案已经提供了所要求的直接解决方案.但是,由于这对于新的Python程序员来说是一个非常常见的陷阱,因此值得添加解释为什么python以这种方式运行,这在" Hitchhikers Python指南 "中很好地概括为" 可变默认参数 ": http:// docs .python-guide.org/EN /最新/写/陷阱/
引用:" 定义函数时,Python的默认参数会被评估一次,而不是每次调用函数时(比如说,就像Ruby一样).这意味着如果你使用一个可变的默认参数并对其进行变异,你将拥有并拥有它将该对象变为该函数的所有未来调用 "
实现它的示例代码:
def foo(element, to=None): if to is None: to = [] to.append(element) return to
在这种情况下并不重要,但您可以使用对象标识来测试None:
if working_list is None: working_list = []
您还可以利用布尔运算符或在python中定义的方式:
working_list = working_list or []
虽然如果调用者给你一个空列表(计为false)并且你的函数修改了他给出的列表,这会出现意外行为.
如果函数的意图是修改传递的参数working_list
,请参阅HenryR的答案(=无,检查内部是否).
但是如果你不打算改变参数,只需使用它作为列表的起点,你可以简单地复制它:
def myFunc(starting_list = []): starting_list = list(starting_list) starting_list.append("a") print starting_list
(或者在这个简单的例子中print starting_list + ["a"]
,我猜这只是一个玩具的例子)
一般来说,改变你的参数是Python中糟糕的风格.完全期望改变对象的唯一函数是对象的方法.改变一个可选参数甚至更为罕见 - 只是在某些调用中发生的副作用真的是最好的接口吗?
如果你从"输出参数"的习惯中做到这一点,那就完全没必要 - 你总是可以将多个值作为元组返回.
如果您这样做是为了有效地构建一长串结果而不构建中间列表,请考虑将其编写为生成器并result_list.extend(myFunc())
在调用时使用.这样你的调用约定仍然非常干净.
经常进行变更可选arg的一种模式是递归函数中隐藏的"备忘录"arg:
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)