为什么"可变的默认参数修复"语法如此丑陋,请问python newbie

cre*_*gox 28 python mutable names

现在跟随我的一系列"python新手问题"并基于另一个问题.

特权

转到http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables并向下滚动到"默认参数值".在那里你可以找到以下内容:

def bad_append(new_item, a_list=[]):
    a_list.append(new_item)
    return a_list

def good_append(new_item, a_list=None):
    if a_list is None:
        a_list = []
    a_list.append(new_item)
    return a_list
Run Code Online (Sandbox Code Playgroud)

在python.org上甚至还有一个"重要的警告",这个例子非常相同,并不是说它"更好".

一种方式来表达它

所以,这里的问题是:为什么在一个已知问题上"好"语法比在一个促进"优雅语法"和"易于使用"的编程语言中那样丑陋?

编辑:

另一种说法

我不是在问为什么或如何发生(感谢Mark的链接).

我问为什么没有更简单的替代内置语言.

我认为更好的方法可能是在def自身中做一些事情,其中name参数将附加到def可变对象中的"本地"或"新" .就像是:

def better_append(new_item, a_list=immutable([])):
    a_list.append(new_item)
    return a_list
Run Code Online (Sandbox Code Playgroud)

我相信有人可以提供更好的语法,但我也猜测必须有一个非常好的解释为什么没有这样做.

Set*_*eth 11

这被称为'可变默认陷阱'.请参阅:http://www.ferg.org/projects/python_gotchas.html#contents_item_6

基本上,a_list在首次解释程序时初始化,而不是每次调用函数时(正如您可能期望的那样).因此,每次调用该函数时,您都没有获得新列表,但是您正在重复使用相同的列表.

我想这个问题的答案是,如果你想将某些东西附加到列表中,就这样做,不要创建一个函数来完成它.

这个:

>>> my_list = []
>>> my_list.append(1)
Run Code Online (Sandbox Code Playgroud)

阅读比以下更清晰,更容易阅读:

>>> my_list = my_append(1)
Run Code Online (Sandbox Code Playgroud)

在实际情况中,如果您需要这种行为,您可能会创建自己的类,其中包含管理其内部列表的方法.


Mik*_*ham 6

def执行语句时评估默认参数,这可能是最合理的方法:它通常是想要的.如果不是这种情况,当环境稍微变化时,可能会导致令人困惑的结果.

区别于魔法local或类似的东西远非理想.Python试图使事情变得非常简单,并且没有明显的,明确的替代当前的样板,而不是诉诸于Python当前具有的相当一致的语义.

  • @cregox请避免说脏话的堆栈溢出. (2认同)

Ale*_*lli 5

函数的极其具体的用例允许您选择传递一个列表进行修改,但除非您专门传递一个列表,否则会生成一个新列表,这绝对不值得使用特殊情况语法。说真的,如果您要多次调用此函数,为什么要对系列中的第一个调用进行特殊处理(仅传递一个参数)以将其与其他每个调用区分开来(这将需要两个参数)能够不断丰富现有的列表)?!例如,考虑类似的东西(当然假设它betterappend做了一些有用的事情,因为在当前的示例中,调用它来代替直接调用是疯狂的.append!-):

def thecaller(n):
  if fee(0):
    newlist = betterappend(foo())
  else:
    newlist = betterappend(fie())
  for x in range(1, n):
    if fee(x):
      betterappend(foo(), newlist)
    else:
      betterappend(fie(), newlist)
Run Code Online (Sandbox Code Playgroud)

这简直是​​疯了,显然应该是,

def thecaller(n):
  newlist = []
  for x in range(n):
    if fee(x):
      betterappend(foo(), newlist)
    else:
      betterappend(fie(), newlist)
Run Code Online (Sandbox Code Playgroud)

始终使用两个参数,避免重复,并构建更简单的逻辑。

引入特殊情况语法鼓励和支持特殊情况用例,而鼓励和支持这种极其特殊的用例实际上没有多大意义——现有的、完全规则的语法对于用例极其罕见的良好用途来说就很好了;- )。