『Python底层原理』--Python属性的工作原理
Python中的属性操作(如获取、设置和删除属性)是我们日常编程中非常常见的操作。
但你有没有想过,当我们写下obj.attr或obj.attr = value时,Python 内部究竟发生了什么?
本文将探讨Python属性的工作原理,并通过简单的代码示例来更好地理解这些概念。
1. 属性的基本操作
在Python中,属性基本操作主要有三种:
- 获取属性值:
value = obj.attr - 设置属性值:
obj.attr = value - 删除属性:
del obj.attr
这些操作看似简单,但它们的实现却依赖于Python的底层机制。
为了更好地理解这些机制,我们需要先了解描述符的概念。
2. 描述符:属性的核心机制
描述符是Python中一个非常重要的概念,它是实现属性功能的核心机制。
描述符是一个对象,它通过实现特定的方法(如__get__、__set__和__delete__)来控制属性的访问、设置和删除。
例如,如下实现一个简单的描述符类:
class Descriptor:
def __get__(self, instance, owner):
return f"从 {instance} 获取属性值"
def __set__(self, instance, value):
print(f"设置 {instance} 的属性值: {value}")
def __delete__(self, instance):
print(f"从 {instance} 中删除属性值")
我们可以将这个描述符作为类属性使用:
obj = MyClass()
print(obj.attr) # 调用 __get__
obj.attr = "Hello" # 调用 __set__
del obj.attr # 调用 __delete__

在CPython中,描述符通过tp_descr_get和tp_descr_set两个函数指针实现。
3. 属性的存储与查找
Python中的属性存储在对象的字典(__dict__)中,或者在类的字典中。
当我们访问属性时,Python会按照以下顺序查找:
- 在实例的
__dict__中查找 - 如果未找到,按照方法解析顺序在类及其父类的
__dict__中查找 - 如果仍未找到,抛出
AttributeError
比如:
class Parent:
x = "Parent"
class Child(Parent):
y = "Child"
obj = Child()
print(obj.x) # 输出 "Parent",从父类中找到
print(obj.y) # 输出 "Child",从子类中找到
4. 类型的属性管理
类型(如int、list)本身也有属性,这些属性的管理方式与普通对象类似,但有一些特殊之处。
因为类型本身是一个对象,它的类型是type,它是一个元类型。
当我们访问类型属性时,Python会按照以下顺序查找:
- 在类型的字典中查找
- 如果未找到,按照 方法解析顺序 在元类型的字典中查找
这里有一个元类型的概念,所谓元类型,是指它的实例是一个类型。
也就是说,正如类用于创建对象一样,元类型是用于创建类的。
Python有一个内置的元类型,称为type,它是所有内置类型中的元类型。
比如我们在Python中创建一个类一般使用下面的方式:
class MyClass:
pass
也可以改成下面这样,和上面是等价的。
MyClass = type('MyClass', (), {})
5. 自定义属性管理
Python允许我们通过定义特殊方法来自定义属性的行为,这些方法包括:
__getattribute__:拦截所有属性访问__getattr__:仅在属性未找到时被调用__setattr__:拦截所有属性设置__delattr__:拦截所有属性删除
下面示例中,自定义了属性的访问和设置。
class MyClass:
def __getattribute__(self, name):
print(f"拦截所有属性的访问: {name}")
return super().__getattribute__(name)
def __getattr__(self, name):
print(f"拦截不存在属性的访问: {name}")
return f"属性 {name} 不存在"
def __setattr__(self, name, value):
print(f"设置属性值: {name} = {value}")
super().__setattr__(name, value)
obj = MyClass()
obj.x = "Hello"
print(obj.x) # 访问存在的属性
print(obj.y) # 访问不存在的属性

当设置属性(obj.x = "Hello")时,调用了 __setattr__;
访问存在的属性(print(obj.x))时,调用了__getattribute__;
访问不存在的属性(print(obj.y))时,调用了__getattribute__和__getattr__,
且是先调用__getattribute__。
6. 总结
Python的属性机制非常强大,它通过描述符、特殊方法和底层的字节码操作实现了灵活的属性管理。
通过理解这些机制,我们可以更好地设计类和对象,优化代码性能,并避免常见的陷阱。
『Python底层原理』--Python属性的工作原理的更多相关文章
- 『无为则无心』Python面向对象 — 51、私有成员变量(类中数据的封装)
目录 1.私有成员变量介绍 (1)私有成员变量概念 (2)私有成员变量特点 (3)私有成员变量体验 2.属性私有化工作原理 3.定义成员变量的标识符规范 4.私有成员变量的获取和设置方式 1.私有成员 ...
- 2018-2019-2 20165316 『网络对抗技术』Exp3:免杀原理与实践
2018-2019-2 20165316 『网络对抗技术』Exp3:免杀原理与实践 一 免杀原理与实践说明 (一).实验说明 任务一:正确使用msf编码器,msfvenom生成如jar之类的其他文件, ...
- 2017-2018-2 20155303 『网络对抗技术』Exp3:免杀原理与实践
2017-2018-2 20155303 『网络对抗技术』Exp3:免杀原理与实践 --------CONTENTS-------- 1. 免杀原理与实践说明 实验说明 基础问题回答 2. 使用msf ...
- 『无为则无心』Python面向对象 — 60、魔法属性
目录 1.魔法属性__name__ 2.魔法属性__bases__ 3.魔法属性__mro__ 4.魔法属性__doc__ 5.魔法属性__module__ 和__class__ 6.魔法属性__di ...
- 『无为则无心』Python面向对象 — 46、类和对象
目录 1.理解类和对象 2.类 3.对象 4.Python中的对象 5.类和对象的定义 (1)定义类 (2)创建对象 (3)练习 6.拓展:isinstance() 函数 1.理解类和对象 (1)类和 ...
- 『无为则无心』Python基础 — 3、搭建Python开发环境
目录 1.Python开发环境介绍 2.Python解释器的分类 3.下载Python解释器 4.安装Python解释器 5.Python解释器验证 1.Python开发环境介绍 所谓"工欲 ...
- 『无为则无心』Python基础 — 4、Python代码常用调试工具
目录 1.Python的交互模式 2.IDLE工具使用说明 3.Sublime3工具的安装与配置 (1)Sublime3的安装 (2)Sublime3的配置 4.使用Sublime编写并调试Pytho ...
- 『无为则无心』Python函数 — 34、lambda表达式
目录 1.lambda的应用场景 2.lambda语法 3.快速入门 4.示例:计算a + b 5.lambda的参数形式 6.lambda的应用 lambda表达式的主要作用就是化简代码. 匿名函数 ...
- python中的函数、生成器的工作原理
1.python中函数的工作原理 def foo(): bar() def bar(): pass python的解释器,也就是python.exe(c编写)会用PyEval_EvalFramEx(c ...
- JVM 的 工作原理,层次结构 以及 GC工作原理
JVM Java 虚拟机 Java 虚拟机(Java virtual machine,JVM)是运行 Java 程序必不可少的机制.JVM实现了Java语言最重要的特征:即平台无关性.原理:编译后的 ...
随机推荐
- 题解:P11007 『STA - R7』Odtlcsu
有个很显然的结论,题目中的 $x$ 与 $y$ 奇偶性相同. 有个更简单的证明,奇数的平方为奇数,偶数的平方为偶数,所以 $x$ 与 $y$ 奇偶性相同. 思路就显而易见了,考虑构造一个长度为 $y$ ...
- Macos 安装md5sum、sha1sum、md5deep、sha1deep
一.安装md5sum和sha1sum 方法一:brew 安装 # brew install md5sha1sum 方法二:编译安装 源码下载地址:http://www.microbrew.org/to ...
- 使用Spring提供的BeanUtils.copyProperties()方法报错:Could not copy property 'xxx' from source to target
使用Spring提供的BeanUtils.copyProperties()方法报错:Could not copy property 'xxx' from source to target; neste ...
- Qt/C++开发经验小技巧281-285
悬停窗体QDockWidget默认在标题栏右键会弹出悬停模块的显示隐藏菜单,如果需要去掉,会发现设置Qt::NoContextMenu或者事件过滤器拦截都是无效的,必须设置 dockWidget-&g ...
- Qt开源作品19-通用数据库翻页查询
一.前言 在Qt与数据库结合编程的过程中,记录一多,基本上都需要用到翻页查看记录,翻页有个好处就是可以减轻显示数据的表格的压力,不需要一次性将数据库表的记录全部显示,也基本上没有谁在一页上需要一次性显 ...
- Qt音视频开发15-mpv事件订阅
一.前言 在使用libmpv的过程中,通过对mpv事件订阅,可以更准确和准时的得知一些事件,比如文件打开成功,播放状态的改变等,而不需要定时器去读取状态,尤其是打开成功这个事件,如果不采用事件订阅,有 ...
- IM通讯协议专题学习(十):初识 Thrift 序列化协议
本文由字节跳动技术团队杨晨曦分享,本文有修订和改动. 1.引言 本文将带你一起初步认识Thrift的序列化协议,包括Binary协议.Compact协议(类似于Protobuf).JSON协议,希望能 ...
- 基于开源IM即时通讯框架MobileIMSDK:RainbowChat v9.0版已发布
关于MobileIMSDK MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级.高度提炼,一套API优雅支持UDP .TCP .WebSocket 三种协议,支持iOS.A ...
- datahub 采集oracle数据 DPI-1047: Cannot locate a 64-bit Oracle Client library: libclntsh.so
datahub 命令行采集oracle 报错如下: datahub ingest -c oracle.yml sqlalchemy.exc.DatabaseError: (cx_Oracle.Data ...
- Solution Set - “让朝阳洒向晚霞,在星空下涂鸦”
目录 0.「UR #12」「UOJ #182」a^-1 + b problem 1.「NOI Simu.」点 2.「集训队互测 2023」「QOJ #5100」卡牌游戏 3.「NOI Simu.」简单 ...