为什么我的实例会改变?

时间:2017-06-09 00:24:30

标签: python class oop

我正在制作一类多项式对象,由字典表示:

  

3 * x ^ 2 + x + 2 == {2:3,1:1,0:2}

这是我的代码中与问题相关的部分:

class Sparse_polynomial():
    def __init__(self, coeffs_dict):
        self.coeffs_dict = coeffs_dict


    def __repr__(self):
        terms = [" + ("+str(self.coeffs_dict[k])+"*x^" + str(k)+")" \
                 for k in sorted(self.coeffs_dict.keys(), reverse=True)]
        terms = "".join(terms)
        return terms[3:]  

    def __neg__(self):
        neg_pol= self.coeffs_dict
        for key in self.coeffs_dict:
            neg_pol[key]= -self.coeffs_dict[key]
        return Sparse_polynomial(neg_pol)

每当我尝试使用__neg__方法时,原始对象都会发生变化。例如:

>>> p1= Sparse_polynomial({1:3,5:1})
>>> p1
(1*x^5) + (3*x^1)
>>> -p1
(-1*x^5) + (-3*x^1)
>>> p1
(-1*x^5) + (-3*x^1)
>>> 

我真的无法理解为什么原来的p1会发生变化。我没有直接修改它,只访问了它的字段。

任何人都可以澄清这样我可以解决这个问题吗?

3 个答案:

答案 0 :(得分:2)

  

我没有直接更改它,只访问了它的字段。

那不对:看看你的代码......

def __neg__(self):
    neg_pol= self.coeffs_dict
    for key in self.coeffs_dict:
        neg_pol[key]= -self.coeffs_dict[key]

你抓住了对系数字典的引用并否定了每个成员。这是副本;它是对原作的引用。

如果您尝试返回单独的字典,请使用可用的多种复制方法之一。一个流行的是来自班级本身的copy

neg_pol = self.coeffs_dict.copy()

检查"手柄"的项目,使用id方法。例如:

print id(self.coeffs_dict), id(neg_pol)

这很容易表明两个变量名称引用同一个对象。

答案 1 :(得分:1)

其他人指出:

neg_pol = self.coeffs_dict

没有创建新的词典,neg_pol只是相同词典的另一个参考,任何更改(例如neg_pol[key] = -self.coeffs_dict[key])都可见变量。

就我个人而言,我更喜欢使用dict-comprehensions创建新的dicts,而不是仅仅使用copy

class Sparse_polynomial():

    # ... your other stuff

    def __neg__(self):
        return Sparse_polynomial({key: -value for key, value in self.coeffs_dict.items()})

答案 2 :(得分:0)

这不是副本,只是对原始字典的引用:

neg_pol = self.coeffs_dict

你想要一个副本,所以你可以改变它而不会弄乱原文:

neg_pol = self.coeffs_dict.copy()

您可能需要查看" How can I assign by value in python"有关如何复制其他可变对象的线索 - Python在如何复制内置函数方面不是很一致,例如list类型没有copy方法,并且大多数人使用切片表示法来复制列表:

new_list = old_list[:]

正如MSeifert所说,dict comprehensions是生成变异副本的好方法:

>>> original_dict = {'a': 2, 'b': 3}
>>> square_dict = {k + "²": v * 2 for k, v in original_dict.items()} 
>>> double_dict
{'a²': 4, 'b²': 9}
>>> original_dict
{'a': 1, 'b': 2}