任何修补Python足够长的人都被以下问题咬伤(或撕成碎片):
def foo(a=[]):
a.append(5)
return a
Run Code Online (Sandbox Code Playgroud)
Python新手希望这个函数总能返回一个只包含一个元素的列表:[5].结果却非常不同,而且非常惊人(对于新手来说):
>>> foo()
[5]
>>> foo()
[5, 5]
>>> foo()
[5, 5, 5]
>>> foo()
[5, 5, 5, 5]
>>> foo()
Run Code Online (Sandbox Code Playgroud)
我的一位经理曾经第一次遇到这个功能,并称其为该语言的"戏剧性设计缺陷".我回答说这个行为有一个潜在的解释,如果你不理解内部,那确实非常令人费解和意想不到.但是,我无法回答(对自己)以下问题:在函数定义中绑定默认参数的原因是什么,而不是在函数执行时?我怀疑经验丰富的行为有实际用途(谁真的在C中使用静态变量,没有繁殖错误?)
编辑:
巴泽克提出了一个有趣的例子.再加上你的大部分评论和特别是Utaal,我进一步阐述了:
>>> def a():
... print("a executed")
... return []
...
>>>
>>> def b(x=a()):
... x.append(5)
... print(x)
...
a executed
>>> b()
[5]
>>> b()
[5, 5]
Run Code Online (Sandbox Code Playgroud)
对我而言,似乎设计决策是相对于放置参数范围的位置:在函数内部还是"与它一起"?
在函数内部进行绑定意味着在调用函数时x有效地绑定到指定的默认值,而不是定义,这会产生一个深层次的缺陷:def在某种意义上,该行将是"混合"的(部分绑定)函数对象)将在定义时发生,并在函数调用时发生部分(默认参数的赋值).
实际行为更加一致:执行该行时,该行的所有内容都会得到评估,这意味着在函数定义中.
python language-design least-astonishment default-parameters
我刚开始使用Python,我不知道什么是memoization以及如何使用它.另外,我可以有一个简化的例子吗?
如何将参数绑定到Python方法以存储一个用于以后调用的nullary仿函数?与C++类似boost::bind.
例如:
def add(x, y):
return x + y
add_5 = magic_function(add, 5)
assert add_5(3) == 8
Run Code Online (Sandbox Code Playgroud) 在Python中将一个可变对象设置为函数中参数的默认值是一个常见的错误.以下是David Goodger撰写的优秀文章中的一个例子:
>>> def bad_append(new_item, a_list=[]):
a_list.append(new_item)
return a_list
>>> print bad_append('one')
['one']
>>> print bad_append('two')
['one', 'two']
Run Code Online (Sandbox Code Playgroud)
之所以出现这种情况的解释是在这里.
现在我的问题是:这个语法有一个很好的用例吗?
我的意思是,如果遇到它的每个人都犯了同样的错误,调试它,理解问题,从而试图避免它,这种语法有什么用?
我想使用实例的属性值将默认参数传递给实例方法:
class C:
def __init__(self, format):
self.format = format
def process(self, formatting=self.format):
print(formatting)
Run Code Online (Sandbox Code Playgroud)
尝试时,我收到以下错误消息:
NameError: name 'self' is not defined
Run Code Online (Sandbox Code Playgroud)
我希望该方法的行为如下:
C("abc").process() # prints "abc"
C("abc").process("xyz") # prints "xyz"
Run Code Online (Sandbox Code Playgroud)
这里有什么问题,为什么这不起作用?我怎么能做这个工作?
嘿大家好,我正在努力简化我的一个作业问题并使代码更好一些.我正在使用的是二叉搜索树.现在我在我的Tree()类中有一个函数,它找到所有元素并将它们放入列表中.
tree = Tree()
#insert a bunch of items into tree
Run Code Online (Sandbox Code Playgroud)
然后我使用我的makeList()函数从树中获取所有节点并将它们放在一个列表中.makeList()我打电话给这个功能tree.makeList(tree.root).对我来说,这似乎有点重复.我已经调用了树对象,tree.所以这tree.root只是浪费一点点打字.
现在makeList函数是:
def makeList(self, aNode):
if aNode is None:
return []
return [aNode.data] + self.makeList(aNode.lChild) + self.makeList(aNode.rChild)
Run Code Online (Sandbox Code Playgroud)
我想让aNode输入一个默认参数,例如aNode = self.root(这不起作用),这样我可以运行这个函数,tree.makeList().
第一个问题是,为什么不起作用?
第二个问题是,有没有办法可以运作?正如你所看到的那样,makeList()函数是递归的,所以我无法在函数的开头定义任何东西,或者我得到一个无限循环.
编辑 以下是所有要求的代码:
class Node(object):
def __init__(self, data):
self.data = data
self.lChild = None
self.rChild = None
class Tree(object):
def __init__(self):
self.root = None
def __str__(self):
current = self.root
def isEmpty(self):
if …Run Code Online (Sandbox Code Playgroud) def save_file(self, outputfilename = self.image_filename):
self.file.read(outputfilename)
....
Run Code Online (Sandbox Code Playgroud)
NameError: name 'self' is not defined在第一行给出.似乎Python不接受它.如何重写代码以免引发异常?
现在跟随我的一系列"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)
我相信有人可以提供更好的语法,但我也猜测必须有一个非常好的解释为什么没有这样做.
当您使用数组参数在Python中定义函数时,该参数的范围是什么?
这个例子来自Python教程:
def f(a, L=[]):
L.append(a)
return L
print f(1)
print f(2)
print f(3)
Run Code Online (Sandbox Code Playgroud)
打印:
[1]
[1, 2]
[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)
我不太确定我是否理解这里发生的事情.这是否意味着数组的范围超出了函数的范围?为什么数组会记住从调用到调用的值?来自其他语言,只有当变量是静态的时候我才会期望这种行为.否则它似乎应该每次重置.实际上,当我尝试以下内容时:
def f(a):
L = []
L.append(a)
return L
Run Code Online (Sandbox Code Playgroud)
我得到了我期望的行为(每次调用都重置了数组).
所以在我看来,我只需要def f(a, L=[]):解释这一行- L变量的范围是什么?