11. 深入理解 Python 描述符及其应用场景详解

Python 中的描述符(Descriptor)是一个用于管理对象属性的特殊对象,它能够在属性的访问、修改和删除时控制这些行为。描述符通过定义特定的协议方法,使得类的属性访问行为变得更加灵活和强大。以下是关于描述符的详细介绍。

1. 描述符的基础概念

描述符是实现了下列方法之一或多个的类:

  • __get__(self, instance, owner):用于获取属性值。
  • __set__(self, instance, value):用于设置属性值。
  • __delete__(self, instance):用于删除属性。

这些方法定义了描述符如何在不同的上下文中与实例进行交互。

2. 描述符的类型

根据实现的方法,描述符可以分为两种类型:

  • 数据描述符:实现了 __get____set__,能够覆盖实例字典中的同名属性。
  • 非数据描述符:只实现了 __get__,不能覆盖实例字典中的同名属性。

3. 创建和使用描述符

为了更好地理解描述符,以下示例演示了一个简单的数据描述符类。

class Descriptor:def __init__(self, name=None):self.name = namedef __get__(self, instance, owner):print(f"获取属性 {self.name}")return instance.__dict__.get(self.name, None)def __set__(self, instance, value):print(f"设置属性 {self.name}{value}")instance.__dict__[self.name] = valuedef __delete__(self, instance):print(f"删除属性 {self.name}")if self.name in instance.__dict__:del instance.__dict__[self.name]class MyClass:attr = Descriptor("attr")obj = MyClass()
obj.attr = 42  # 输出:设置属性 attr 为 42
print(obj.attr)  # 输出:获取属性 attr 并返回 42
del obj.attr  # 输出:删除属性 attr

4. 描述符的应用场景

  • 属性验证:使用描述符来验证数据类型、范围等。
  • 数据封装:实现只读属性或其他特定行为。
  • 惰性计算属性:可以在第一次访问时计算值,然后缓存结果。
示例:实现属性验证描述符
class Typed:def __init__(self, name, expected_type):self.name = nameself.expected_type = expected_typedef __get__(self, instance, owner):return instance.__dict__.get(self.name)def __set__(self, instance, value):if not isinstance(value, self.expected_type):raise TypeError(f"属性 {self.name} 必须是 {self.expected_type}")instance.__dict__[self.name] = valueclass Person:name = Typed("name", str)age = Typed("age", int)p = Person()
p.name = "Alice"  # 正常设置
p.age = 30        # 正常设置
# p.age = "30"    # 会引发 TypeError

5. 描述符的工作原理

当访问一个属性时,Python 会按照以下顺序查找:

  1. 检查对象的实例字典(__dict__)。
  2. 检查类中的数据描述符。
  3. 如果找不到数据描述符,检查实例字典。
  4. 检查类中的非数据描述符。
  5. 检查父类的字典。

因此,数据描述符会优先于实例字典,而非数据描述符不会覆盖实例字典中的同名属性。

6. 描述符和 property() 的关系

property() 是 Python 内置的简单描述符,用于快速定义访问器方法。

class MyClass:def __init__(self):self._x = Nonedef get_x(self):return self._xdef set_x(self, value):self._x = valuex = property(get_x, set_x)obj = MyClass()
obj.x = 10  # 等效于调用 set_x
print(obj.x)  # 等效于调用 get_x

property() 是描述符的简化版,提供了更易读的属性访问控制。

7. 高级用法和注意事项

  • 缓存属性:描述符可用于实现惰性计算属性,节省计算开销。
  • 元类结合:在元类中结合描述符,可以实现更复杂的行为控制。
  • 不要滥用描述符:描述符提供了强大的功能,但会增加代码的复杂度。应在有特定需求时使用。

总结

Python 描述符是管理属性访问行为的强大工具,适合实现自定义的属性验证、数据封装和计算属性。通过理解其工作原理和使用场景,开发者可以更灵活地控制对象行为,提高代码的可维护性和扩展性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/17303.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

突破工业管理新高度:AI多模态引擎赋能设备维护管理

结合AI技术,可以帮助企业提升设备维护效率和管理复杂信息的能力。以下是一个详细流程和思路: 1. 项目背景概述 在高端制造业领域,如飞机、轮船、光刻机等设备的操作手册及零件图纸涉及大量的零配件信息和操作维护流程。传统方式难以高效管理…

C++重写和重定义和重载

重写 概念: 重写发生在类的继承体系中,是指在派生类中重新定义基类中已声明为虚函数(使用 virtual 关键字修饰)的函数。其目的是让派生类根据自身的需求对基类的虚函数提供不同的具体实现,从而实现运行时多态。 规则及…

centos7在使用yum源安装依赖时报错

1.在centos7中使用yum命令时候报错如下类似信息: Loading mirror speeds from cached hostfile Could not retrieve mirrorlist http://mirrorlist.centos.org/?release7&archx86_64&repoos&infrastock error was 14: curl#6 - "Could not resol…

小版本大不同 | Navicat 17 新增 TiDB 功能

近日,Navicat 17 迎来了小版本更新。此次版本新增了对 PingCap 公司的 TiDB 开源分布式关系型数据库的支持,进一步拓展了 Navicat 的兼容边界。即日起,Navicat 17 所有用户可免费升级至最新版本,通过 Navicat 工具实现 TiDB 数据库…

python 编程 在 Matplotlib 中 默认预定的所有颜色,可以使用多种方法来指定颜色,包括预定义的颜色名称、十六进制颜色代码、

在 Matplotlib 中,可以使用多种方法来指定颜色,包括预定义的颜色名称、十六进制颜色代码、RGB 元组等。如果你想要一个比较深的颜色,你可以选择一些预定义的深色名称,或者使用较低的亮度值来定义自己的颜色。 以下是一些预定义的…

【基于Java Springboot敬老院管理系统

一、作品包含 源码数据库设计文档万字全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue、Element-ui 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA/eclipse 数据库…

JRebel插件,全教程

JRebel是一套JavaEE开发工具。相信大家都用过,但是频繁的需要激活,已经让java开发者烦不胜烦。 本篇文章来给大家解决这个烦恼。当然没有用过的同行,我也跟大家介绍一下: 简单来说,Jrebel 可快速实现热部署,在本地开发…

PPPoE技术详解

一 , 背景 随着运营商对宽带接入技术要求的不断提高,以xDSL,CableModem和以太网为主的几种宽带接入技术在用户管理和计费等方面的不足开始显露,已无法满足运营商的需求。 在众多的技术中,以太网接入方式经济实惠&…

[JAVA]MyBatis环境配置介绍

什么是MyBatis环境配置? MyBatis是基于JDBC对数据库进行操作,在我们进行数据操作时,我们需要告诉MyBatis我们连接哪个数据库,ip地址,数据库名称,用户名密码等。以此来进行环境配置。 首先,MyB…

Javascirpt时区——脱坑指南

最近业务反馈了一个约课功能的问题,澳大利亚的用户反馈,无法进行选课。排查之后发现是时区不对引起的,由于时区的偏差已经超过时间,导致无法选课。 这里对js中处理时区的问题做一些总结。 时区 时区(Time Zone&#xf…

不用来回切换,一个界面管理多个微信

你是不是也有多个微信号需要管理? 是不是也觉得频繁切换账号很麻烦? 是不是也想提升多账号管理的效率? 在工作中,好的辅助工具,能让我们的效率加倍增长! 今天, 就给大家分享一个多微管理工具…

每日OJ题_牛客_AB32【模板】哈夫曼编码_C++_Java

目录 牛客_AB32【模板】哈夫曼编码 题目解析 C代码 Java代码 牛客_AB32【模板】哈夫曼编码 【模板】哈夫曼编码_牛客题霸_牛客网 描述: 给出一个有n种字符组成的字符串,其中第ii种字符出现的次数为ai​。请你对该字符串应用哈夫曼编码,…

UDP协议

​ UDP协议 前置知识一、应用层的进程为什么要bind端口号二、如何确定网络中的一个进程三、进程 服务 协议 端口之间的关系四、常见的协议对应的端口五、一些命令六、一个进程能不能绑定多个端口号,一个端口号能不能被多个进程绑定七、对任何一个协议报文的认识 UD…

KkFileView4.1.0部署文档--linux

先看下官方文档:kkFileView - 在线文件预览 环境要求中的JDK8如果没有的,需先安装JDK8,这里不做展示。 第二个office相关环境要求在linux中会自动下载安装,不用管。 1、下载地址 Linux 或 MacOS 版: https://kkfil…

[论文笔记]An LLM Compiler for Parallel Function Calling

引言 今天带来一篇优化函数调用的论文笔记——An LLM Compiler for Parallel Function Calling。 为了简单,下文中以翻译的口吻记录,比如替换"作者"为"我们"。 当前的函数(工具)调用方法通常需要对每个函数进行顺序推理和操作&…

基于JAVA的资源检索系统(源码+定制+开发)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

展望:多模态融合与marker推断

技术进步使得利用高维、高通量、多尺度的生物医学数据从多个角度研究患者和疾病成为可能。在肿瘤学中,正在生成大量数据,从分子、组织病理学到临床记录。深度学习的引入极大地促进了生物医学数据的分析。然而,大多数方法都侧重于单一模态&…

AI在电商平台中的创新应用:提升销售效率与用户体验的数字化转型

1. 引言 AI技术在电商平台的应用已不仅仅停留在基础的数据分析和自动化推荐上。随着人工智能的迅速发展,越来越多的电商平台开始将AI技术深度融合到用户体验、定价策略、供应链优化、客户服务等核心业务中,从而显著提升运营效率和用户满意度。在这篇文章…

基于Java Springboot餐厅点餐系统(加入商家版)

一、作品包含 源码数据库设计文档万字全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA 数据库:MySQL5.7…

NeRF在农业领域的应用-------------(1)

一、Exploring Accurate 3D Phenotyping in Greenhouse through Neural Radiance Fields(通过神经辐射场探索温室中精确的三维表型分析) 1.摘要 在精准农业中,准确收集植物表型对于优化可持续农业实践至关重要。 在受控实验室环境中进行的传…