首页 > 解决方案 > 为什么类属性并不总是作为键出现在实例的字典中?

问题描述

我在关于属性的这一部分中阅读了有关 Python 中的 OOP 的内容,并且对下面的示例感到震惊。

我不明白为什么实例的字典(class赋予新属性)为空:

class Robot(object):
    pass

x = Robot()
Robot.brand = "Kuka"
x.brand

输出:

'Kuka'

x.brand = "Thales"
Robot.brand

输出:

'Kuka'

y = Robot()
y.brand

输出:

'Kuka'

Robot.brand = "Thales"
y.brand

输出:

'Thales'

x.brand

输出:

'Thales'

如果你查看__dict__字典,你可以看到发生了什么:

x.__dict__

输出:

{'brand': 'Thales'}

y.__dict__

输出:

{}

来自同一网站的另一句话:

如果您尝试访问 y.brand,Python 会首先检查“brand”是否是 y 的键。__dict__字典。如果不是,Python 会检查“品牌”是否是机器人的键。__dict__. 如果是这样,则可以检索该值。

我的问题是:为什么要y.__dict__给出一个空字典?其背后的逻辑和机制是什么?

标签: pythonclassobjectoopattributes

解决方案


我们可以用它id(<object>)来检查发生了什么。

声明一个新的空类 Robot

    class Robot(object):
    ...     pass
    ... 
    Robot
    <class '__main__.Robot'>
    Robot.__dict__
    mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Robot' objects>, '__weakref__': <attribute '__weakref__' of 'Robot' objects>, '__doc__': None})

Robot类的新实例

    x = Robot()
    x
    <__main__.Robot object at 0x0000022811C8A978>

x实例为空

    x.__dict__
    {}

brand定义了新的类属性

Robot.brand = "Kuka"
Robot.brand
'Kuka'

如果我们尝试访问x.brand,Python 将查找brandin x.__dict__,什么也没有,所以它会去Robot.__dict__查找类属性brand

x.brand
'Kuka'

我们可以验证我们实际上看到的是相同的

id(Robot.brand)
2371120205752
id(x.brand)
2371120205752

brand定义了新的实例属性

x.brand = "Thales"

并且类属性brand保持不变

Robot.brand
'Kuka'

我们可以验证我们实际上看到了两个不同的属性

id(x.brand)
2371119992200
id(Robot.brand)
2371120205752

新实例y已创建并且为空

y = Robot()
y.__dict__
{}

我们可以验证这是一个新的:

id(y)
2371119989200

如果我们尝试访问y.brand,Python 会查找brandin y.__dict__,但什么也没找到,然后去Robot.__dict__查找类属性brand

y.brand
'Kuka'

我们可以验证 id 是否相同Robot.brandy参考也是如此Robot.brand

id(y.brand)
2371120205752

如果我们修改类属性brand

Robot.brand = "Thales"
id(Robot.brand)
2371119992200

y.brand被修改是因为此时不是实例属性而是对类属性的引用Robot.brand。我们可以检查 idy.brand是否与Robot.brand.

y.brand
'Thales'
id(y.brand)
2371119992200

现在我们可以检查它x有一个实例属性x.brand

x.brand
'Thales'
x.__dict__
{'brand': 'Thales'}

但 y 什么都没有,因为它只是一个参考Robot.brand

y.__dict__
{}

并且 Robot.brand 具有brand带值的类属性Thales

Robot.__dict__
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Robot' objects>, '__weakref__': <attribute '__weakref__' of 'Robot' objects>, '__doc__': None, 'brand': 'Thales'})

在此处查看附加说明:https ://github.com/leocjj/0123/blob/master/Python/0123P_9_Classes_objects.txt


推荐阅读