为什么python字典在我启动一个新的类实例时会记住上一个实例的值?

为什么python字典在我启动一个新的类实例时会记住上一个实例的值?,python,class,dictionary,instance,Python,Class,Dictionary,Instance,可能重复: 当我试图写一个像下面这样的类时,我有一件很奇怪的事情。在第3行,我必须将参数newdata的一个新副本放到self.data中,否则,当我启动一个新的类实例时,类仍然会记住上一个实例的值。参见下面的示例,请注意第3行的两个版本代码的唯一区别 class Pt(object): def __init__(self,newdata={}):

可能重复:

当我试图写一个像下面这样的类时,我有一件很奇怪的事情。在第3行,我必须将参数newdata的一个新副本放到self.data中,否则,当我启动一个新的类实例时,类仍然会记住上一个实例的值。参见下面的示例,请注意第3行的两个版本代码的唯一区别

class Pt(object):                                                               
    def __init__(self,newdata={}):                                              
        self.data=newdata.copy()                                                       
        if self.data == {}:                                                     
            self._taglist = []                                                  
        else:                                                                   
            self._taglist = self.data.keys()                                    
    def add_tag(self,tag=None):                                                 
        self.data[tag]={'x':[0,1,2,3,4]}                                        
        self._taglist.append(tag)                                               


In [49]: pt = Pt()

In [50]: pt.add_tag('b')

In [51]: pt.add_tag('a')

In [52]: pt.data
Out[52]: {'a': {'x': [0, 1, 2, 3, 4]}, 'b': {'x': [0, 1, 2, 3, 4]}}

In [53]: pt2 = Pt()

In [54]: pt2._taglist
Out[54]: []


我猜发生第二种情况是因为:newdata和self.data都引用同一个对象(但这怎么可能发生,值应该从右到左给出,而不是从左到右),所以当我使用“add_tag”方法更新self.data时,newdata也会被更新。然而,我认为当我通过pt2=Pt()启动一个新实例时,newdata应该使用默认值({}),它还能从pt1保留旧值吗

您的问题是复制字典,然后创建具有相同值的新字典。这意味着词典中的列表是相同的,因此当您修改它们时,所有词典中的列表都会被修改


你要做的是——这不仅仅是复制字典,还要复制列表。

中已经很好地解释了为什么和所有这些。因此,这里只是一个快速的帮助,如何解决您的问题

由于保留了默认参数对象,所以永远不要将可变对象用作默认参数值。相反,您应该定义一个固定值,通常是
None
,作为默认值,然后初始化默认对象。因此,您的构造函数将如下所示:

def __init__(self, newdata=None):
    if newdata is None:
        newdata = {}
    # ...

您不应该使用可变对象作为默认值。我不会说永远不要使用可变对象作为默认值。有时,这正是您想要的行为。@JerryB这似乎不太可能,但如果确实如此,您应该使用其他机制来访问共享对象,而不是将其用作默认参数,因为这显然会让人困惑。当然,这肯定很少见,我试图给出的任何例子都是人为的。但稀有和从不一样。就像我在80年代上大学时,他们反复强调“永远不要使用goto!”但我还没有处理过任何没有goto的语言,只是命名了其他语言,并且具有内置的限制/保护。@JerryB Python没有goto。这是除非你调用循环和条件语句goto来命名其他东西——这将是荒谬的,因为硬件是如何工作的,所以你不能使用它们。正是这样:每个控制结构实际上都是goto的一种形式。这确实是重点:你不能用某种形式的跳跃来完成任何非平凡的算法。像if和for这样的事情会迫使您以阅读您的代码的人更容易理解的方式这样做。
def __init__(self, newdata=None):
    if newdata is None:
        newdata = {}
    # ...