Python函数调用正在放弃范围,有状态,无法初始化参数?

got*_*nes 5 python scope

在我大胆地提交错误报告之前,我想我会在这里用更聪明的Pythonistas检查我的假设.我今天遇到了一个令人困惑的案例,所以我把它改成了一个玩具示例,如下所示:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

"""
A little script to demonstrate that a function won't re-initialize its
list parameters between calls, but instead allows them to retain state.

"""

def bleedscope(a=[], b=[]):
    """
    On each call, unless explicitly passed, both `a` and `b` should be
    initialized as empty lists.

    """

    c = a
    if b:
        c.extend(b)
    return len(c)


x = bleedscope(b=[1])
print x     # Should be 1, as expected.
x = bleedscope(b=[2])
print x     # Expect also to be 1, but it's 2. `a` is retained.
x = bleedscope(a=[1])
print x     # Now 1 as expected.
x = bleedscope(b=[3])
print x     # 1 as expected? No, it's 3! Insanity!
Run Code Online (Sandbox Code Playgroud)

我认为函数参数在函数范围内是局部的,并且在函数调用结束时被垃圾收集,永远不会在它们之间保留状态.我已经在Python 2.5.2和Python 2.6.1上测试了上面的脚本,但我的理解不是结果.争论a当然保留了大多数这些电话之间的状态; 最令人困惑的是最后一次呼叫bleedscope,它跳过前一个呼叫的状态,然后返回到第二个呼叫的状态(即,[1, 2]).[我建议在你最喜欢的调试器中运行它来亲眼看看.如果你没有,我建议将Winpdb作为一个可靠的FOSS独立Python调试器.]

这里发生了什么?

Kai*_*Kai 15

在Python中,默认参数值仅在解析def调用时初始化.对于对象(例如列表),它会在调用之间重用.看看这篇关于它的文章,它也提供了必要的解决方法:

http://effbot.org/zone/default-values.htm

  • 任何可变对象对于默认值来说都是一个糟糕的选择——可变对象(如列表)不能以这种方式使用。 (2认同)

Unk*_*own 8

这是你的问题:

def bleedscope(a=[], b=[]):
Run Code Online (Sandbox Code Playgroud)

它应该是

def bleedscope(a=None, b=None):
    if a is None: a = []
    if b is None: b = []
Run Code Online (Sandbox Code Playgroud)

默认参数仅在解析函数时执行一次,因此每次使用相同的2个列表.


Joh*_*hin 5

FAQ里有解释