首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python类变量和实例变量混淆

Python类变量和实例变量混淆
EN

Stack Overflow用户
提问于 2017-02-07 07:16:17
回答 2查看 66关注 0票数 3

关于下面的代码,我得到了一些稍微意外的行为:

代码语言:javascript
复制
class MyClass(object):
   value = 5

object1 = MyClass()
object2 = MyClass()

print object1.value #This displays 5
print object2.value #This displays 5
print MyClass.value #This displays 5 

#So far so good

object1.value = 6

print object1.value #This displays 6
print object2.value #This displays 5
print MyClass.value #This displays 5

#Still good, but the confusing part is coming up...

MyClass.value = 10

print object1.value #This displays 6. I was expecting it to be 10!
print object2.value #This displays 10
print MyClass.value #This displays 10

正如您所看到的,我正在更改变量的实例版本,并获得预期的结果。但是,当我将MyClass.Value更改为10时,我希望它会更改所有实例的值。但也许我的理解是不正确的。

任何帮助都将深表感谢。

EN

回答 2

Stack Overflow用户

发布于 2017-02-07 07:27:02

首先,object1object2都是MyClass的实例,没有任何特定于实例的变量。然后更改object1.value。它仍然是MyClass的成员,但当你请求object1.value时,得到的结果是6,因为一旦它看到自己有MyClass的值,它就不会去看它的值。这给出了到目前为止预期的行为。

当你把MyClass.value改成10,任何时候你查找MyClass.value都会得到10,当你直接查找或者通过object2查找时就会发生这种情况。但是,object1仍然有自己的value,因为您将其设置为6。因此,当您请求object1.value时,它会在object1中查找value并看到6。它没有注意到MyClass的版本发生了变化。

这不会发生在object2上,因为它没有关联的value;在object2中查找失败,所以它尝试查找object2.__class__.value。因为object2MyClass的一个实例,所以object2.__class__MyClass,它给出了10。

如果你说del object1.value,那么查询object1.value,你会从MyClass得到10,就像object2一样。

票数 1
EN

Stack Overflow用户

发布于 2017-02-08 13:12:49

在幕后发生的事情是,当您分配一个实例属性时,该实例的私有字典(__dict__)会更新,但类的__dict__不会更新。前者优先用于查找请求的属性,如果找不到它(在前几行,通常用于object2),则使用类的__dict__来查找该属性。

具体地说:

属性赋值和删除操作会更新实例的字典,而不会更新类的字典。如果类具有__setattr__()__delattr__()方法,则会调用该方法,而不是直接更新实例字典。

(强调我的。从the Python documentation on the standard type hierarchy in the data model;您需要找到“类实例”小节,第二段。它前面的段落处理实例属性查找顺序。(整个小节和前面的小节“自定义类”可能会更好地理解概念;可能会读几次,因为它有些精简。)

打印相关实例、类和属性的is和(在本例中) __dict__属性通常有助于我了解其背后发生的事情。id并不能保证你看到的是相同的对象,但在我使用CPython的时候,它通常是有效的。

您的代码,调整为打印以下内容:

代码语言:javascript
复制
from __future__ import print_function

class MyClass(object):
    value = 5

object1 = MyClass()
object2 = MyClass()

print(object1.value, id(object1.value), object1.__dict__)
print(object2.value, id(object2.value), object2.__dict__)
print(MyClass.value, id(MyClass.value), MyClass.__dict__)

object1.value = 6
print(object1.value, id(object1.value), object1.__dict__)
print(object2.value, id(object2.value), object2.__dict__)
print(MyClass.value, id(MyClass.value), MyClass.__dict__)

MyClass.value = 10
print(object1.value, id(object1.value), object1.__dict__)
print(object2.value, id(object2.value), object2.__dict__)
print(MyClass.value, id(MyClass.value), MyClass.__dict__)

以及我得到的输出(为了阅读方便,我插入了一些额外的换行符和空格):

代码语言:javascript
复制
5 4325640816 {}
5 4325640816 {}
5 4325640816 {'__doc__': None, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, 
    '__dict__': <attribute '__dict__' of 'MyClass' objects>, 
    '__module__': '__main__', 'value': 5}

6 4325640848 {'value': 6}
5 4325640816 {}
5 4325640816 {'__doc__': None, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, 
    '__dict__': <attribute '__dict__' of 'MyClass' objects>, 
    '__module__': '__main__', 'value': 5}

6 4325640848 {'value': 6}
10 4325640976 {}
10 4325640976 {'__doc__': None, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, 
    '__dict__': <attribute '__dict__' of 'MyClass' objects>, 
    '__module__': '__main__', 'value': 10}

ids因运行和系统而异,在这里,'value'总是在MyClass.__dict__中最后打印,但是您可以看到哪些属性发生了变化,哪些属性实际上是相同的,以及__dict__属性是如何更新的。

(注意:请勿自行修改__dict__属性。一般来说,不要以任何方式使用它,也不是用来读的。让其他内置方法和函数来处理。)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42079021

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档