<p>将对同一个(可变)对象的引用与对不同对象的引用混淆起来确实是一个“问题”(所有非函数性语言都会遇到这种情况,即具有可变对象和引用的语言)。初学者Python代码中经常出现的一个错误是误用了一个可变的默认值,例如:</p>
<pre><code>def addone(item, alist=[]):
alist.append(item)
return alist
</code></pre>
<p>如果目的是让<code>addone</code>保持自己的状态(并将一个增长的列表返回给连续的调用方),则此代码可能是正确的,就像<code>static</code>数据在C中可以工作一样;如果编码人员错误地假设在每次调用时都会生成一个新的空列表,那么这段代码就不正确了。在</p>
<p>习惯于函数式语言的初学者也可能会被Python内置容器中的<a href="http://en.wikipedia.org/wiki/Command-query_separation" rel="noreferrer">command-query separation</a>设计决策所迷惑:那些没有特别返回内容的方法(即绝大多数变异方法)什么都不返回(具体地说,它们返回<code>None</code>),它们正在“原地”完成所有工作。来自误解的错误很容易被发现,例如</p>
^{pr2}$
<p>几乎可以肯定是一个bug,它将一个条目附加到名为<code>alist</code>的列表中,然后将name <code>alist</code>重新绑定到<code>None</code>(调用<code>append</code>的返回值)。在</p>
<p>虽然我提到的第一个问题是关于早期绑定,可能会误导那些认为绑定是延迟绑定的人,但是也有一些问题是相反的,即有些人的期望是早期绑定,而绑定则是延迟绑定。例如(使用假设的GUI框架…):</p>
<pre><code>for i in range(10):
Button(text="Button #%s" % i,
click=lambda: say("I'm #%s!" % i))
</code></pre>
<p>这将显示10个按钮,表示“Button#0”、“Button#1”等,但是,当单击时,每个按钮都将<code>say</code>,它是{<cd9>},因为{<cd11>}</strong>中的<code>i</code><strong>是晚绑定的(带有词法闭包)。一个修复方法是利用参数<em>的默认值是</em>早期绑定的这一事实(正如我在第一个问题中指出的那样!-)最后一行改成</p>
<pre><code> click=lambda i=i: say("I'm #%s!" % i))
</code></pre>
<p>现在<code>lambda</code>的<code>i</code>是一个带有默认值的参数,不再是一个自由变量(通过词法闭包查找),因此代码按预期工作(当然还有其他方法)。在</p>