Python函数调用范围泄漏,状态不当,参数无法初始化?

5 投票
4 回答
1064 浏览
提问于 2025-04-15 12:04

在我敢于提交一个错误报告之前,我想先在这里向更有经验的Python爱好者请教一下我的想法。我今天遇到了一个让人困惑的情况,所以我把它简化成了一个小例子,如下所示:

#!/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!

我原本以为函数的参数在函数内部是局部的,函数调用结束后会被垃圾回收,也就是说它们之间不会保留状态。但是,我在Python 2.5.2和Python 2.6.1上测试了上面的代码,结果却和我的理解不一致。参数a在大多数调用之间确实保留了状态;最让人困惑的是最后一次调用bleedscope时,它跳过了之前调用的状态,回到了第二次调用结束时的状态(也就是[1, 2])。 [我建议你在自己喜欢的调试工具中运行这个代码,看看结果。如果你没有调试工具,我推荐Winpdb,这是一个不错的开源Python调试器。]

这到底是怎么回事呢?

4 个回答

5

在这个常见问题解答中有一个解释。

8

这是你的问题:

def bleedscope(a=[], b=[]):

应该是这样的:

def bleedscope(a=None, b=None):
    if a is None: a = []
    if b is None: b = []

默认参数只在函数被解析的时候执行一次,所以每次调用这个函数时,都会使用同样的两个列表。

15

在Python中,默认参数的值只有在定义函数的时候才会被初始化。如果这个参数是一个对象,比如列表,那么在多次调用这个函数时,它会被重复使用。你可以看看这篇文章,里面也提供了必要的解决方法:

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

撰写回答