为什么"可变的缺省参数的解决方法"一语法是很丑陋的,要求python新手
题
现在下面 我的一系列"蟒新手的问题" 并且基于 另一个问题.
特权
去 http://python.net/~goodger/项目/pycon/2007/习惯用/讲义。html#其他语言有变量 和下滚到"缺省参数值"。还有你可以找到如下:
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
甚至还有一个 "重要的预警"上python.org 与此同样的实例,虽然没有真正说的是"更好"。
一个办法把它
因此,问题是:为什么是的 "好的"法在一个已知的问题 丑陋的样,在一种编程语言, 促进"优雅语法"和"易于使用的"?
编辑:
另一个办法把它
我不是在问 为什么,或者它是如何发生的 (谢谢标记的链接)。
我要问 为什么没有更简单的替代建成的语言.
我觉得一个更好的办法可能会能够做些什么的 def
本身,在其名参数将连接到一个"地方",或"新的"内 def
, 、可变对象。是这样的:
def better_append(new_item, a_list=immutable([])):
a_list.append(new_item)
return a_list
我敢肯定有人可以跟一个更好的语法,但我也猜测必须有一个非常好的解释说明为什么这个还没有完成。
解决方案
默认计算参数的时候 def
发言被执行,这是可能的最合理的方法:它往往是什么被通缉。如果不是这种情况下,它可能导致混淆的结果时,环境变化的一点。
区分用魔法 local
法或类似的东西是远远不够理想。蟒蛇试图使事情很平和,没有明显、清楚的替代目前的样板,不诉诸搞不一致的语义蟒蛇目前拥有.
其他提示
这就是所谓的'可变的默认设置的陷阱'.参见: http://www.ferg.org/projects/python_gotchas.html#contents_item_6
基本上, a_list
初始化时该计划是第一个解释,不是每次你打电话的功能(作为你可能期望从其他语言)。所以你没有得到一个新的清单每次你打电话的功能,但你们再利用同一个。
我猜测回答的问题是,如果你要追加的东西的列表,只要做到这一点,不要创造一个功能做到这一点。
这样的:
>>> my_list = []
>>> my_list.append(1)
是更清楚和更容易阅读于:
>>> my_list = my_append(1)
在实际情况下,如果你需要的这种行为,你可能会创建自己的类其具有方法来管理它的内部名单。
非常具体使用情况的功能,可以让你 任选 通过一名单的修改,但是产生一个新的名单,除非你具体做过一个在,绝对不值得特殊情况下的语法。说真的,如果你制作一些调用这一功能,为什么你会想要特殊的情况的第一个电话系列(通过只有一个参数)以区别,从每一个其他人(这将需要两个参数能够保持丰富的现有清单)?!E.g., 考虑喜欢的东西(假设的课程, 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)
这简直是疯了,并且应该 显然 是的,相反,
def thecaller(n):
newlist = []
for x in range(n):
if fee(x):
betterappend(foo(), newlist)
else:
betterappend(fie(), newlist)
总是使用两个论点,避免重复,并且建立更简单的逻辑。
引入的特殊情况下的语法 鼓励和支持 特别壳使用的情况下,并没有真的没有多大意义,鼓励和支持这个非常奇特的一个--现有的,完全正规语法是很好的使用情况是非常罕见的 很好的 使用;-).
我编辑这个答案,包括思想自许多评论意见张贴在的问题。
例如您得到的是 有缺陷.它修改的列表中,你通过它作为一个副作用。如果这就是你如何打算功能的工作,它不会有意义的默认的说法。也不会有意义的返回更新名单。没有一个默认的说法,该问题消失。
如果意图是返回的一个新名单,你需要让一个 复制 输入的名单。蟒蛇喜欢的事情是明确的,所以这是你做的副本。
def better_append(new_item, a_list=[]):
new_list = list(a_list)
new_list.append(new_item)
return new_list
对于一些不同的东西,你可以做一个发电机,可以采取的一清单或发电机作为输入:
def generator_append(new_item, a_list=[]):
for x in a_list:
yield x
yield new_item
我觉得你是在误解,蟒蛇把可变和不可改变的缺省参数,以不同的方式;这是不真实的。相反,不可改变的参数使你改变你的代码在一个微妙的方式来做正确的事情。把你的例子并使其适用于串而不是一个清单:
def string_append(new_item, a_string=''):
a_string = a_string + new_item
return a_string
这种代码并不能改变过去了string-这不可能,因为串不可改变的。它创建一个新的字符,并分配a_string到,新的串。默认的说法可以使用一遍又一遍,因为它不会改变你做了它的一个副本的开始。
什么如果你是不是说名单,但有关AwesomeSets,一类,你只是定义的?你想来定义".本地" 每一个舱?
class Foo(object):
def get(self):
return Foo()
local = property(get)
可能可以工作,但将获得旧的真快,真的很快。很快,"如果一个没有:a=CorrectObject()"模式将成为第二本性,和你不会找到它丑陋的-你会发现很有启发性。
问题不是一个语法,但是一个语义--的价值观的缺省参数进行评估,在功能的定义的时间,不能执行时间。
也许你不应该定义这两个功能良好的和坏的。你可以使用第一个列表或字典实施的地方修改相应的对象。这种方法可以给你头痛如果你不知道怎么可变对象的工作,但鉴于您知道你在做什么,它是确定在我的意见。
所以你有两个不同的方法通过的参数提供不同的行为。这是良好的,我不会改变它。
我觉得你是混乱的优雅语法用法糖。蟒蛇的语法进行通信两种方法显然,它只是发生,正确的办法似乎不太优雅(在线法)于不正确的办法。但由于不正确的做法,是嗯...不正确的,它的优雅是无关紧要的。为什么喜欢的东西你证明在better_append是实现不了的,我猜想 There should be one-- and preferably only one --obvious way to do it.
王牌微小收益的典范。
这是更好的比good_append()、海事组织:
def ok_append(new_item, a_list=None):
return a_list.append(new_item) if a_list else [ new_item ]
你可能还要格外小心,并检查a_list是一个列表...