问题:避免默认参数为空列表的pythonic方法是什么?
有时,使用默认参数(一个空列表)似乎很自然。但是Python在这些情况下会产生意外的行为。
例如,如果我有一个功能:
def my_func(working_list = []):
working_list.append("a")
print(working_list)
第一次调用它时,默认设置将起作用,但是此后的调用将更新现有列表(每个调用一个“ a”)并打印更新的版本。
那么,什么是获得我想要的行为的Python方法(每次调用都会有一个新列表)?
回答 0
def my_func(working_list=None):
if working_list is None:
working_list = []
working_list.append("a")
print(working_list)
回答 1
现有答案已经按要求提供了直接解决方案。但是,由于这对于新Python程序员来说是一个非常常见的陷阱,因此有必要添加解释python为何采用这种方式的解释,在《Python的Hitchhikers指南》中很好地总结为“ Mutable Default Arguments ”: http:// docs .python-guide.org / en / latest / writing / gotchas /
Quote:“ Python的默认参数在定义函数时进行一次评估,而不是在每次调用函数时都进行评估(例如Ruby)。这意味着,如果您使用可变的默认参数并对它进行突变,您将拥有将该对象也更改为将来对函数的所有调用 ”
实现它的示例代码:
def foo(element, to=None):
if to is None:
to = []
to.append(element)
return to
回答 2
在这种情况下,这并不重要,但是您可以使用对象标识来测试None:
if working_list is None: working_list = []
您还可以利用布尔运算符or在python中的定义方式:
working_list = working_list or []
尽管如果调用者给您一个空列表(该列表为false)作为working_list并期望您的函数修改他提供的列表,这将出乎意料。
回答 3
如果该函数的目的是修改作为参数传递的参数working_list
,请参见HenryR的答案(= None,检查内部是否为None)。
但是,如果您不想改变该参数,只需将其用作列表的起点,则可以简单地将其复制:
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())
在调用时使用。这样,您的调用约定仍然非常干净。
经常更改可选arg的一种模式是递归函数中的隐藏“ memo” 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)
回答 4
我可能没什么意思,但是请记住,如果您只想传递可变数量的参数,则pythonic方法是传递元组*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}
回答 5
已经提供了正确的正确答案。我只是想提供另一种语法来编写您想做的事情,例如,当您想创建一个带有默认空列表的类时,我会发现它更漂亮:
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 []
此代码段使用if else运算符语法。我特别喜欢它,因为它是一个整齐的小单行,没有冒号等,而且读起来几乎像普通的英语句子。:)
您可以写
def myFunc(working_list=None):
working_list = [] if working_list is None else working_list
working_list.append("a")
print working_list
回答 6
我参加了UCSC扩展类 Python for programmer
def Fn(data = []):
a)是个好主意,这样您的数据列表在每次调用时都开始为空。
b)是一个好主意,以便对函数的所有调用(在调用中不提供任何参数)都将获得空列表作为数据。
c)是一个合理的想法,只要您的数据是字符串列表即可。
d)是个坏主意,因为默认[]将累积数据,而默认[]将随后续调用而改变。
回答:
d)是个坏主意,因为默认[]将累积数据,而默认[]将随后续调用而改变。