字典和类的意外Python行为

时间:2013-10-10 04:37:24

标签: python

class test:
    def __init__(self):
        self.see=0
        self.dic={"1":self.see}

examine=test()
examine.see+=1
print examine.dic["1"]
print examine.see

结果为0和1,这没有任何意义。

    print id(examine.dic["1"])
    print id(examine.see)

他们也有不同的内存地址

但是,如果你使用相同的例子但是你有一个数组而不是变量。你得到了预期的输出。

有任何解释吗?

这给出了预期的输出:

class test:
    def __init__(self):
        self.see=[0]
        self.dic={"1":self.see}

examine=test()
examine.see[0]+=1
print examine.dic["1"][0]
print examine.see[0]

6 个答案:

答案 0 :(得分:4)

简短回答:

数组/ list是可变的,而整数/ int则不是。

答案 1 :(得分:3)

列表是可变的(它们可以就地更改),当您更改列表时,相同的对象会更新(ID不会更改,因为不需要新对象)。

整数是不可变的 - 这意味着要改变某些东西的价值,你必须创建一个新的对象,它将具有不同的id。字符串以相同的方式工作,你会遇到同样的问题"如果您设置self.see = 'a',然后执行examine.see += ' b'

>>> a = 'a'
>>> id(a)
3075861968L
>>> z = a
>>> id(z)
3075861968L
>>> a += ' b'
>>> id(a)
3075385776L
>>> id(z)
3075861968L
>>> z
'a'
>>> a
'a b'

在Python中,名称指向值;和值由Python管理。 id()方法返回的唯一标识符,而不是名称

任意数量的名称都可以指向相同的。这意味着,您可以拥有多个名称,这些名称都链接到相同的ID。

首次创建类对象时,名称see指向整数对象的值,该对象的值为1。然后,当您创建类dic时,"1"键现在指向see指向的同一对象;这是1

由于1(整数类型的对象)是不可变的 - 每当您更新它时,原始对象都会被替换并创建一个新对象 - 这就是id()的返回值发生变化的原因。

Python足够聪明,知道还有一些其他名称指向" old"价值,所以它将它保存在内存中。

但是,现在你有两个对象;字典仍然指向" old"一,see现在指向新的。

当您使用列表时,Python不需要创建新对象,因为它可以修改列表而不会破坏它;因为列表是可变的。现在,当您创建一个列表并为其指向两个名称时,两个名称都指向同一个对象。当您更新此对象(通过添加值,或删除值或更改其值)时,相同的对象会更新 - 因此指向它的所有内容都将更新"更新"值。

答案 2 :(得分:2)

examine.dic["1"]examine.see确实有不同的位置,即使前者的初始值是从后者复制的。

根据您使用数组的情况,您不会更改examine.see的值:而是更改examine.see[0],这会更改它指向的数组的内容(这是别名examine.dic["1"])。

答案 3 :(得分:1)

当您执行self.dic={"1":self.see}时,此时dict值将设置为self.see的值。如果您稍后执行examine.see += 1,则会将examine.see设置为新值。这对dict没有影响,因为dict被设置为self.see;它不知道“继续观察”名称self.see以查看是否指向不同的值。

如果您将self.see设置为列表,然后执行examine.see += [1],则不会将examine.see设置为新值,而是更改现有值。这将在dict中可见,因为再次将dict设置为,并且该值可以更改。

有时a += ba设置为新值,有时会更改现有值。发生哪一个取决于a的类型;您需要知道examine.see知道examine.see += something的作用。

答案 4 :(得分:1)

其他人已经解决了可变性/拳击问题。你似乎要求的是后期绑定。这是可能的,但有点违反直觉,并且可能有更好的解决方案来解决您的根本问题...如果我们知道它是什么。

class test:
  @property
  def dic(self):
    self._dic.update({'1': self.see})
    return self._dic
  def __init__(self):
    self.see = 0
    self._dic = {}

>>> ex=test()
>>> ex.see
0
>>> ex.see+=1
>>> ex.see
1
>>> ex.dic
{'1': 1}
>>> ex.see+=1
>>> ex.dic
{'1': 2}

事实上,在这个人为的例子中,它甚至有点危险,因为返回self._dic消费者可以直接修改字典。但那没关系,因为你不需要在现实生活中这样做。如果您想要self.see的值,只需获取self.see的值。

事实上,看起来这就是你想要的:

class test:
  _see = 0
  @property
  def see(self):
    self._see+=1
    return self._see

或者,你知道,只是itertools.count():P

答案 5 :(得分:0)

这个解决方案对我有用。随意使用它。

class integer:
    def __init__(self, integer):
        self.value=integer
    def plus(self):
        self.value=self.value+1
    def output(self):
        return self.value

该解决方案将可变类型int替换为其地址用作引用的类。 此外,您可以更改类对象,并且更改适用于字典指向的内容。它有点像指针/数据结构。