-1
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)

它们也有不同的内存地址

但是,如果您使用相同的示例,但在 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]
4

6 回答 6

4

简短的回答:

数组/ lists 是可变的,而整数/ ints 不是。

于 2013-10-10T04:41:49.777 回答
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. 然后,当你创建你的 classdic时,"1"键现在指向同一个对象see;这是1

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

Python 足够聪明,知道还有一些其他名称指向“旧”值,因此它将其保存在内存中。

但是,现在您有两个对象;并且字典仍然指向“旧”的,see现在指向新的。

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

于 2013-10-10T04:48:38.633 回答
2

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

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

于 2013-10-10T04:40:31.863 回答
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

于 2013-10-10T04:55:22.443 回答
1

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

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

问题是有时会a += b设置a为新值,有时会更改现有值。发生哪一种取决于a; 你需要知道什么examine.see是知道做什么examine.see += something

于 2013-10-10T04:42:47.500 回答
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 替换为地址用作引用的类。此外,您可以更改类对象并将更改应用于字典指向的内容。它在某种程度上是一个指针/数据结构。

于 2013-10-10T05:17:20.610 回答