-1

我有以下设置:

def returnList(arg=["abc"]):
    return arg

list1 = returnList()
list2 = returnList()

list2.append("def")

print("list1: " + " ".join(list1) + "\n" + "list2: " + " ".join(list2) + "\n")

print(id(list1))
print(id(list2))

输出:

list1: abc def
list2: abc def

140218365917160
140218365917160

我可以看到 arg=["abc"] 返回相同默认列表的副本,而不是每次都创建一个新列表。

我试过做

def returnList(arg=["abc"][:]):

def returnList(arg=list(["abc"])):

是否可以获得一个新列表,或者每次我想要某种默认值时都必须在方法内复制列表?

4

2 回答 2

5

我见过的最好的模式只是

def returnList(arg=None):
    if arg is None: arg = ["abc"]
    ...

唯一的潜在问题是,如果您希望None在此处成为有效输入,在这种情况下,您将不得不使用不同的哨兵值。

您的方法的问题是args 默认参数被评估一次。您执行什么复制运算符并不重要,因为它只是被评估而不是与函数一起存储。在每个函数调用期间都不会重新评估它。

更新:

我不想错过 nneonneo 的评论,使用新鲜object的作为哨兵会很好。

default = object()
def f(x = default):
    if x is default:
        ...
于 2013-08-01T10:39:26.260 回答
1

你想要的就是你自己的陈述:你每次都想要一个新的值副本。简单地调用一个函数不会自动执行任何操作,因此无法仅通过句法技巧来完成此操作。但是你可以使用装饰器来做你想做的事:

import copy

def keepDefaults(f):
  defaults = f.func_defaults
  def wrapped(*args, **kwargs):
    f.func_defaults = copy.deepcopy(defaults)
    return f(*args, **kwargs)
  return wrapped

@keepDefaults
def f(a=[1]):
  return a

f()[0].append(2)
print f()  # will print "[1]" instead of "[1, 2]"
于 2013-08-01T10:56:16.930 回答