为什么通过python默认变量初始化变量会在对象实例化中保持状态?

cbr*_*ker 6 python arguments

我今天遇到了一个有趣的python bug,其中实例化一个类似乎反复出现状态.在以后的实例化调用中,已经定义了变量.

我将问题归结为以下类/ shell交互.我意识到这不是初始化类变量的最佳方法,但它肯定不应该像这样.这是一个真正的错误还是这个"功能"?:d

tester.py:

class Tester():
        def __init__(self):
                self.mydict = self.test()

        def test(self,out={}):
                key = "key"
                for i in ['a','b','c','d']:
                        if key in out:
                                out[key] += ','+i
                        else:   
                                out[key] = i 
                return out

Python提示:

Python 2.6.6 (r266:84292, Oct  6 2010, 00:44:09) 
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin
>>> import tester
>>> t = tester.Tester()
>>> print t.mydict
{'key': 'a,b,c,d'}
>>> t2 = tester.Tester()
>>> print t2.mydict
{'key': 'a,b,c,d,a,b,c,d'}

Sti*_*gma 11

几乎所有Python用户都遇到过一次或两次这样的功能.主要用于缓存等,以避免重复冗长的计算(简单的记忆,真的),虽然我相信人们已经找到了它的其他用途.

原因是def语句只执行一次,即定义函数时.因此,初始化值仅创建一次.对于引用类型(与不可更改的不可变类型相反),如列表或字典,这最终会成为一个可见且令人惊讶的陷阱,而对于值类型,它会被忽视.

通常,人们会这样解决:

def test(a=None):
    if a is None:
        a = {}
    # ... etc.
Run Code Online (Sandbox Code Playgroud)


Sam*_*lan 5

一般来说,默认方法参数不应该是可变的。而是这样做:

def test(self, out=None):
   out = out or {}
   # other code goes here.
Run Code Online (Sandbox Code Playgroud)

有关为什么需要这样做以及为什么它是 Python 语言的“功能”而不是错误的更多详细信息,请参阅这些链接。

  • `out = out 或 {}` 不仅有一种令人讨厌的味道,而且如果调用者传入他们自己的空映射对象也会失败。`if out is None: out = {}` 是可取的。 (5认同)