news 2026/6/15 15:58:39

python属性底层查找机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
python属性底层查找机制

在Python中,对象(实例)对类属性赋值的行为需要结合Python的属性查找机制和命名空间规则来理解。类属性属于类本身(所有实例共享),而实例属性属于单个实例。

通过实例对类属性赋值时,不会直接修改类属性本身,而是会在实例的命名空间中创建一个同名的实例属性(覆盖类属性的访问)。但如果类属性是可变对象(如列表、字典),通过实例修改其内容会影响所有实例(因为共享同一引用)。

1、底层机制:属性查找与命名空间

Python的属性查找遵循以下顺序(简单情况下):实例命名空间(obj.__dict__)→ 类命名空间(cls.__dict__)→ 父类命名空间 → ...未找到则抛异常。当通过实例访问属性时,优先在实例的 __dict__中查找,若未找到,则到类的 __dict__中查找(类属性)。

若通过实例赋值(如obj.attr = value),会直接在实例的 __dict__中创建或修改属性,不会影响类属性(除非显式操作类的 __dict__)。

2、代码解释

先看下面这段简单的代码输出是多少?

#!/usr/bin/python3 class A(object): x = 1 class B(A): pass class C(A): pass print(A.x,B.x,C.x) B.x = 2 print(A.x,B.x,C.x) A.x = 3 print(A.x,B.x,C.x)

输出结果如下:

1 1 1
1 2 1
3 2 3

Q:为什么改变了A.x的值还会改变C.x的值,但是同时B.x值却没有改变?

A:这个答案的关键是,在Python中,类变量在内部是作为字典处理的。如果一个变量的名字没有在当前类的字典中发现,将搜索祖先类(比如父类)直到被引用的变量名被找到(如果这个被引用的变量名既没有在自己所在的类又没有在祖先类中找到,会引发一个AttributeError异常)。

因此,在父类中设置x = 1会使得类变量x在引用该类和其任何子类中的值为1,这就是因为第一个print语句的输出是 1 1 1。

随后,如果任何它的子类重写了该值(例如,执行语句B.x = 2),然后,该值仅仅在子类中被改变。这就是为什么第二个print语句的输出是1 2 1。

最后,如果该值在父类中被改变(例如,我们执行语句A.x = 3),这个改变会影响到任何未重写该值的子类当中的值(在这个示例中被影响的子类是C)。这就是为什么第三个print输出是 3 2 3 。

那么下面这段代码的输出又是多少呢?

#!/usr/bin/python3 class A(object): x = 1 class B(A): pass class C(A): pass b = B() c = C() a = A() print(a.x,b.x,c.x) # 1 1 1 b.x = 2 print(a.x,b.x,c.x) # 1 2 1 a.x = 3 print(a.x,b.x,c.x) # 3 2 1

输出结果如下:

1 1 1
1 2 1
3 2 1

下面部分对代码添加了部分额外打印的内容以及注释

#!/usr/bin/python3 class A(object): x = 1 class B(A): pass class C(A): pass b = B() c = C() a = A() print(a.__dict__,A.__dict__) #{} {'__module__': '__main__', 'x': 1, #'__dict__': <attribute '__dict__' of 'A' objects>, #'__weakref__': <attribute '__weakref__' of 'A' objects>, #'__doc__': None} print(b.__dict__,B.__dict__) # {} {'__module__': '__main__', '__doc__': None} print(c.__dict__,C.__dict__) # {} {'__module__': '__main__', '__doc__': None} # 不管是在类B还是类C的类对象或者实例对象的命名空间中都没有属性x,通过python的属性查找机制,只能在父类对象A的命名空间中找到属性x的值 print(a.x,b.x,c.x) # 1 1 1 # 注意,这里是对实例命名空间进行操作,在实例对象b的命名空间中添加属性x的值 b.x = 2 print(b.__dict__,B.__dict__) # {'x': 2} {'__module__': '__main__', '__doc__': None} print(a.x,b.x,c.x) # 1 2 1 # 注意,这里是对实例命名空间进行操作,在实例对象a的命名空间添加属性x值为3,不影响类命名空间中的属性x a.x = 3 print(a.__dict__,A.__dict__) # {'x': 3} # {'__module__': '__main__', 'x': 1, # '__dict__': <attribute '__dict__' of 'A' objects>, # '__weakref__': <attribute '__weakref__' of 'A' objects>, #'__doc__': None} # 实例c在自身的实例和类对象命名空间中都没找到属性x,在父类对象A的类命名空间中找到属性x的值为1 print(a.x,b.x,c.x) # 3 2 1
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 3:31:57

资深工程师亲授:行为树调试与优化的6步黄金流程

第一章&#xff1a;行为树的优化在复杂的游戏AI或自动化系统中&#xff0c;行为树&#xff08;Behavior Tree&#xff09;作为决策核心组件&#xff0c;其执行效率直接影响整体性能。随着节点数量增加和逻辑嵌套加深&#xff0c;未优化的行为树可能导致严重的性能瓶颈。因此&am…

作者头像 李华
网站建设 2026/6/14 12:06:05

最近在工控项目里折腾了一把信捷XD5 PLC和台达DT330温控器的通讯,整个过程就像玩解谜游戏——接线、调参数、写程序环环相扣。直接上干货,先看核心通讯程序

信捷XD PLC与台达DT330温控器通讯程序输出启停控制(XJXD-1)功能&#xff1a;通过信捷XD5&#xff0c;实现对台达DT330温控器 设定温度&#xff0c;读取温度&#xff0c;控制温控器输出启停&#xff0c;反应灵敏&#xff0c;通讯稳定可靠。 程序采用轮询方式器件&#xff1a;信捷…

作者头像 李华
网站建设 2026/6/14 22:46:30

dify 创建gitlab账号

目录 1、环境: 2、获取gitlab访问令牌 3、dify安装[JSON 处理]插件 ​4、dify创建工作流应用 5、dify详细配置 6、校验 1、环境 dify版本Version 1.5.1 gitlab版本号:gitlab企业版16.10 完成配置的工作流截图。 工作流导出的DSL:创建gitlab账号demo.yml 链接: https…

作者头像 李华
网站建设 2026/6/15 11:42:23

Carsim Simulink联合仿真-基于LQR/模糊PID/滑模控制的横摆稳定性控制系统

Carsim Simulink联合仿真-基于LQR/模糊PID/滑模控制的横摆稳定性控制系统 综合跟随理想横摆角速度的方法和抑制汽车质心侧偏角的汽车稳定性控制方法&#xff0c;以线性二自由度车辆操纵特性模型为控制目标&#xff0c;基于汽车横摆力矩与车辆状态偏差之间的动力学关系建立了控制…

作者头像 李华
网站建设 2026/6/15 12:56:52

原型链查找的 O(N) 开销:在超长继承链下属性访问的性能损耗实验

各位同仁&#xff0c;各位技术爱好者&#xff0c;大家好&#xff01;今天&#xff0c;我们将深入探讨一个在JavaScript编程中看似基础&#xff0c;实则蕴含深刻性能考量的话题&#xff1a;原型链查找的O(N)开销&#xff0c;以及它在超长继承链下对属性访问性能可能造成的损耗。…

作者头像 李华
网站建设 2026/6/15 13:47:38

计及需求响应的区域综合能源系统双层优化调度策略 参考文档:计及需求响应的区域综合能源系统双层优...

计及需求响应的区域综合能源系统双层优化调度策略参考文档&#xff1a;计及需求响应的区域综合能源系统双层优化调度策略 matlabyalmipcplex 主要内容&#xff1a;需求响应聚合商通过需求响应聚合用户的可转移负荷和可削减负荷&#xff0c;提高区域综合能源系统运行的灵活性和经…

作者头像 李华