- Python 基础
- Python - 首页
- Python - 概述
- Python - 历史
- Python - 特性
- Python vs C++
- Python - Hello World 程序
- Python - 应用领域
- Python - 解释器
- Python - 环境搭建
- Python - 虚拟环境
- Python - 基本语法
- Python - 变量
- Python - 数据类型
- Python - 类型转换
- Python - Unicode 系统
- Python - 字面量
- Python - 运算符
- Python - 算术运算符
- Python - 比较运算符
- Python - 赋值运算符
- Python - 逻辑运算符
- Python - 位运算符
- Python - 成员运算符
- Python - 身份运算符
- Python - 运算符优先级
- Python - 注释
- Python - 用户输入
- Python - 数字
- Python - 布尔值
- Python 控制语句
- Python - 控制流
- Python - 决策制定
- Python - If 语句
- Python - If else
- Python - 嵌套 If
- Python - Match-Case 语句
- Python - 循环
- Python - for 循环
- Python - for-else 循环
- Python - While 循环
- Python - break 语句
- Python - continue 语句
- Python - pass 语句
- Python - 嵌套循环
- Python 函数 & 模块
- Python - 函数
- Python - 默认参数
- Python - 关键字参数
- Python - 仅限关键字参数
- Python - 位置参数
- Python - 仅限位置参数
- Python - 可变参数
- Python - 变量作用域
- Python - 函数注解
- Python - 模块
- Python - 内置函数
- Python 字符串
- Python - 字符串
- Python - 字符串切片
- Python - 修改字符串
- Python - 字符串连接
- Python - 字符串格式化
- Python - 转义字符
- Python - 字符串方法
- Python - 字符串练习
- Python 列表
- Python - 列表
- Python - 访问列表项
- Python - 修改列表项
- Python - 添加列表项
- Python - 删除列表项
- Python - 循环列表
- Python - 列表推导式
- Python - 排序列表
- Python - 复制列表
- Python - 合并列表
- Python - 列表方法
- Python - 列表练习
- Python 元组
- Python - 元组
- Python - 访问元组项
- Python - 更新元组
- Python - 解包元组
- Python - 循环元组
- Python - 合并元组
- Python - 元组方法
- Python - 元组练习
- Python 集合
- Python - 集合
- Python - 访问集合项
- Python - 添加集合项
- Python - 删除集合项
- Python - 循环集合
- Python - 合并集合
- Python - 复制集合
- Python - 集合运算符
- Python - 集合方法
- Python - 集合练习
- Python 字典
- Python - 字典
- Python - 访问字典项
- Python - 修改字典项
- Python - 添加字典项
- Python - 删除字典项
- Python - 字典视图对象
- Python - 循环字典
- Python - 复制字典
- Python - 嵌套字典
- Python - 字典方法
- Python - 字典练习
- Python 数组
- Python - 数组
- Python - 访问数组项
- Python - 添加数组项
- Python - 删除数组项
- Python - 循环数组
- Python - 复制数组
- Python - 反转数组
- Python - 排序数组
- Python - 合并数组
- Python - 数组方法
- Python - 数组练习
- Python 文件处理
- Python - 文件处理
- Python - 写入文件
- Python - 读取文件
- Python - 重命名和删除文件
- Python - 目录
- Python - 文件方法
- Python - OS 文件/目录方法
- Python - OS 路径方法
- 面向对象编程
- Python - OOPs 概念
- Python - 类 & 对象
- Python - 类属性
- Python - 类方法
- Python - 静态方法
- Python - 构造函数
- Python - 访问修饰符
- Python - 继承
- Python - 多态
- Python - 方法重写
- Python - 方法重载
- Python - 动态绑定
- Python - 动态类型
- Python - 抽象
- Python - 封装
- Python - 接口
- Python - 包
- Python - 内部类
- Python - 匿名类和对象
- Python - 单例类
- Python - 包装器类
- Python - 枚举
- Python - 反射
- Python 错误 & 异常
- Python - 语法错误
- Python - 异常
- Python - try-except 块
- Python - try-finally 块
- Python - 抛出异常
- Python - 异常链
- Python - 嵌套 try 块
- Python - 用户自定义异常
- Python - 日志记录
- Python - 断言
- Python - 内置异常
- Python 多线程
- Python - 多线程
- Python - 线程生命周期
- Python - 创建线程
- Python - 启动线程
- Python - 连接线程
- Python - 线程命名
- Python - 线程调度
- Python - 线程池
- Python - 主线程
- Python - 线程优先级
- Python - 守护线程
- Python - 线程同步
- Python 同步
- Python - 线程间通信
- Python - 线程死锁
- Python - 中断线程
- Python 网络
- Python - 网络
- Python - Socket 编程
- Python - URL 处理
- Python - 泛型
- Python 库
- NumPy 教程
- Pandas 教程
- SciPy 教程
- Matplotlib 教程
- Django 教程
- OpenCV 教程
- Python 杂项
- Python - 日期 & 时间
- Python - 数学
- Python - 迭代器
- Python - 生成器
- Python - 闭包
- Python - 装饰器
- Python - 递归
- Python - 正则表达式
- Python - PIP
- Python - 数据库访问
- Python - 弱引用
- Python - 序列化
- Python - 模板
- Python - 输出格式化
- Python - 性能测量
- Python - 数据压缩
- Python - CGI 编程
- Python - XML 处理
- Python - GUI 编程
- Python - 命令行参数
- Python - 文档字符串
- Python - JSON
- Python - 发送邮件
- Python - 扩展
- Python - 工具/实用程序
- Python - GUIs
- Python 高级概念
- Python - 抽象基类
- Python - 自定义异常
- Python - 高阶函数
- Python - 对象内部
- Python - 内存管理
- Python - 元类
- Python - 使用元类进行元编程
- Python - 模拟和存根
- Python - 猴子补丁
- Python - 信号处理
- Python - 类型提示
- Python - 自动化教程
- Python - Humanize 包
- Python - 上下文管理器
- Python - 协程
- Python - 描述符
- Python - 诊断和修复内存泄漏
- Python - 不可变数据结构
- Python 有用资源
- Python - 问答
- Python - 在线测验
- Python - 快速指南
- Python - 参考
- Python - 速查表
- Python - 项目
- Python - 有用资源
- Python - 讨论
- Python 编译器
- NumPy 编译器
- Matplotlib 编译器
- SciPy 编译器
Python - 描述符
Python 描述符
Python 描述符 是一种自定义对象属性的访问、赋值和删除的方式。它们提供了一种强大的机制,通过定义获取、设置和删除其值的方法来管理属性的行为。描述符通常用于实现属性、方法和属性验证。
描述符 是任何实现了至少一个方法(例如 __get__、__set__ 和 __delete__)的对象。这些方法控制如何访问和修改属性的值。
Python 描述符如何工作?
当在实例上访问属性时,Python 会在实例的类中查找该属性。如果找到该属性并且它是一个描述符,则 Python 会调用相应的描述符方法,而不是简单地返回属性的值。这允许描述符控制在属性访问期间发生的事情。
描述符协议是一种低级机制,Python 中许多高级功能都使用它,例如属性、方法、静态方法和类方法。描述符可用于实现延迟加载、类型检查和计算属性等模式。
描述符方法
Python 描述符 包括三个主要方法,即 __get__()、__set__() 和 __delete__()。正如我们上面已经讨论过的,这些方法分别控制属性访问、赋值和删除的行为。
1. __get__() 方法
描述符中的 __get__() 方法 是 Python 中描述符协议的关键部分。它被调用以从实例或类中检索属性的值。了解 __get__() 方法 的工作原理对于创建可以以复杂方式管理属性访问的自定义描述符至关重要。
语法
以下是 Python 描述符 __get__ 方法 的语法:
def __get__(self, instance, owner): """ instance: the instance that the attribute is accessed through, or None when accessed through the owner class. owner: the owner class where the descriptor is defined. """
参数
以下是此方法的参数:
- self: 描述符实例。
- instance: 访问属性的类的实例。当通过类而不是实例访问属性时,它为 None。
- owner: 拥有描述符的类。
示例
以下是 __get__() 方法的基本示例,其中在访问 obj.attr 时返回存储的值 _value:
class Descriptor: def __get__(self, instance, owner): if instance is None:return self return instance._value class MyClass: attr = Descriptor() def __init__(self, value): self._value = value obj = MyClass(42) print(obj.attr)
输出
42
2. __set__() 方法
__set__() 方法 是 Python 中描述符协议的一部分,用于控制设置属性值的行为。当由描述符管理的属性被赋予新值时,__set__() 方法 被调用,允许用户自定义或强制执行赋值规则。
语法
以下是 Python 描述符 __set__() 方法 的语法:
def __set__(self, instance, value): """ instance: the instance of the class where the attribute is being set. value: the value to assign to the attribute. """
参数
以下是此方法的参数:
- self: 描述符实例。
- instance: 设置属性的类的实例。
- value: 赋给属性的值。
示例
以下是 __set__() 方法的基本示例,其中确保赋给 attr 的值是整数:
class Descriptor: def __set__(self, instance, value): if not isinstance(value, int): raise TypeError("Value must be an integer") instance._value = value class MyClass: attr = Descriptor() def __init__(self, value): self.attr = value obj = MyClass(42) print(obj.attr) obj.attr = 100 print(obj.attr)
输出
<__main__.Descriptor object at 0x000001E5423ED3D0> <__main__.Descriptor object at 0x000001E5423ED3D0>
3. __delete__() 方法
描述符协议中的 __delete__() 方法 允许我们控制从实例中删除属性时发生的事情。当删除属性时,这对于管理资源、清理或强制执行约束很有用。
语法
以下是 Python 描述符 __delete__() 方法 的语法:
def __delete__(self, instance): """ instance: the instance of the class from which the attribute is being deleted. """
参数
以下是此方法的参数:
- self: 描述符实例。
- instance: 删除属性的类的实例。
示例
以下是 __set__() 方法的基本示例,其中确保赋给 attr 的值是整数:
class LoggedDescriptor: def __init__(self, name): self.name = name def __get__(self, instance, owner): return instance.__dict__.get(self.name) def __set__(self, instance, value): instance.__dict__[self.name] = value def __delete__(self, instance): if self.name in instance.__dict__: print(f"Deleting {self.name} from {instance}") del instance.__dict__[self.name] else: raise AttributeError(f"{self.name} not found") class Person: name = LoggedDescriptor("name") age = LoggedDescriptor("age") def __init__(self, name, age): self.name = name self.age = age # Example usage p = Person("Tutorialspoint", 30) print(p.name) print(p.age) del p.name print(p.name) del p.age print(p.age)
输出
Tutorialspoint 30 Deleting name from <__main__.Person object at 0x0000021A1A67E2D0> None Deleting age from <__main__.Person object at 0x0000021A1A67E2D0> None
Python 描述符的类型
在 Python 中,描述符 可以根据它们实现的方法大致分为两种类型。它们是:
- 数据描述符
- 非数据描述符
让我们详细了解这两种 Python 描述符,以便我们更好地理解。
1. 数据描述符
数据描述符 是一种 Python 描述符,它定义了 __get__() 和 __set__() 方法。这些描述符优先于实例属性,这意味着即使存在同名的实例属性,也会始终调用描述符的 __get__() 和 __set__() 方法。
示例
下面是一个数据描述符的示例,它确保属性始终为整数,并记录访问和修改操作。
class Integer: def __get__(self, instance, owner): print("Getting value") return instance._value def __set__(self, instance, value): print("Setting value") if not isinstance(value, int): raise TypeError("Value must be an integer") instance._value = value def __delete__(self, instance): print("Deleting value") del instance._value class MyClass: attr = Integer() # Usage obj = MyClass() obj.attr = 42 print(obj.attr) obj.attr = 100 print(obj.attr) del obj.attr
输出
Setting value Getting value 42 Setting value Getting value 100 Deleting value
2. 非数据描述符
非数据描述符是 Python 中的一种描述符类型,它仅定义了__get__()方法。与数据描述符不同,非数据描述符可以被实例属性覆盖。这意味着如果存在同名的实例属性,则它将优先于非数据描述符。
示例
以下是非数据描述符的一个示例,如果实例上未设置属性,则它提供一个默认值。
class Default: def __init__(self, default): self.default = default def __get__(self, instance, owner): return getattr(instance, '_value', self.default) class MyClass: attr = Default("default_value") # Usage obj = MyClass() print(obj.attr) obj._value = "Tutorialspoint" print(obj.attr)
输出
default_value Tutorialspoint
数据描述符与非数据描述符
了解 Python 描述符中数据描述符和非数据描述符之间的区别对于有效地利用它们的功能至关重要。
标准 | 数据描述符 | 非数据描述符 |
---|---|---|
定义 | 实现 __get__()、__set__() 方法,以及可选的 __delete__() 方法。 | 仅实现 __get__() 方法。 |
方法 | __get__(self, instance, owner) __set__(self, instance, value) __delete__(self, instance)(可选) |
__get__(self, instance, owner) |
优先级 | 优先于实例属性。 | 被实例属性覆盖。 |
用例 | 属性验证和强制执行, 托管属性(例如,属性), 记录属性访问和修改, 强制执行只读属性。 |
方法绑定, 缓存和, 提供默认值。 |
最后,我们可以说 Python 中的描述符提供了一种强大的机制来管理属性的访问和修改。了解数据描述符和非数据描述符之间的区别以及它们的适当用例对于创建健壮且可维护的 Python 代码至关重要。
通过利用描述符协议,开发人员可以实现高级行为,例如类型检查、缓存和只读属性。