当前位置: 首页 > news >正文

Python 描述符

文章目录

      • 类型:
      • 数据描述符:
      • 方法描述符:
      • 描述符的要包括以下几点:
      • 方法描述符
      • 实现缓存

描述符(Descriptor)是 Python 中一个非常强大的特性,它允许我们自定义属性的访问行为。使用描述符,我们可以创建一些特殊的属性,在访问这些属性时执行自定义的逻辑,如数据验证、属性计算等。

类型:

**数据描述符:**用于修改属性的访问和修改行为。
**方法描述符:**用于修改方法的行为。

数据描述符:

**get:**在属性被访问时被调用。
**set:**在属性被设置时被调用。
**delete:**在属性被删除时被调用。

方法描述符:

**call:**在方法被调用时被调用。

下面我们来看一个具体的例子:

class MyDescriptor:def __init__(self, initial_value=None):self._value = initial_valuedef __get__(self, instance, owner):print(f"Getting value: {self._value}")return self._valuedef __set__(self, instance, value):print(f"Setting value to: {value}")self._value = valuedef __delete__(self, instance):print("Deleting value")del self._valueclass MyClass:my_attr = MyDescriptor(42)obj = MyClass()
print(obj.my_attr)  # Output: Getting value: 42
obj.my_attr = 100   # Output: Setting value to: 100
del obj.my_attr     # Output: Deleting value

在这个例子中,我们定义了一个 MyDescriptor 类,它实现了三个描述符协议方法:__get____set____delete__。这些方法分别在访问、设置和删除属性时被调用。

MyClass 中,我们定义了一个 my_attr 属性,它使用 MyDescriptor 作为描述符。当我们访问、设置或删除 obj.my_attr 时,相应的描述符方法会被调用,并执行我们自定义的逻辑。

描述符的要包括以下几点:

  1. 数据验证: 可以在 __set__ 方法中添加数据验证逻辑,确保属性值符合预期。
  2. 属性计算: 在 __get__ 方法中实现动态计算属性值的逻辑。
  3. 属性缓存: 使用描述符可以实现属性值的缓存,提高访问性能。
  4. 懒加载: 描述符可以用于实现懒加载,即在第一次访问属性时才计算或加载属性值。
  5. 属性权限控制: 可以使用描述符实现只读、只写或读写属性。
  6. 属性依赖管理: 描述符可以用于管理属性之间的依赖关系,确保属性值的一致性。

下面是一个的代码示例,实现了一个带有数据验证和属性缓存的描述符:

class CachedProperty:def __init__(self, getter):self.getter = getterself._cache = {}def __get__(self, instance, owner):if instance is None:return selfif instance not in self._cache:self._cache[instance] = self.getter(instance)return self._cache[instance]def __set__(self, instance, value):self._cache[instance] = valuedef __delete__(self, instance):if instance in self._cache:del self._cache[instance]class Person:def __init__(self, name, age):self.name = nameself.age = age@CachedPropertydef full_name(self):print("Calculating full name...")return f"{self.name} Smith"@propertydef age(self):return self._age@age.setterdef age(self, value):if value < 0:raise ValueError("Age cannot be negative")self._age = valuep = Person("John", 30)
print(p.full_name)  # Output: Calculating full name... John Smith
print(p.full_name)  # Output: John Smith (from cache)p.age = 40
print(p.age)  # Output: 40p.age = -10  # Raises ValueError: Age cannot be negative

在这个场景下,selfinstance 的区别如下:

  1. self:

    • self 代表的是 Person 类本身的实例,也就是 Person 类的一个对象。
    • __get__ 方法中,self 指向的是 Person 类的 age 属性本身,而不是某个特定的 Person 对象。
  2. instance:

    • instance 代表的是正在访问 age 属性的 Person 对象实例。
    • __get__ 方法中,instance 指向的是调用 age 属性的具体 Person 对象,比如上例中的 person 对象。

简单来说:

  • self 指向的是属性本身(即 age 属性),而 instance 指向的是正在访问该属性的对象实例。
  • self 是属性级别的,而 instance 是对象级别的。
  • owner 是属性的类对象

这个区别很重要,因为在 __get__ 方法中,我们需要根据具体的 Person 对象实例(instance)来计算年龄,而不是直接使用 self(即 age 属性本身)。

方法描述符

class Calculator:def __init__(self):self.num1 = 0self.num2 = 0def __call__(self, a, b):self.num1 = aself.num2 = breturn selfdef add(self):return self.num1 + self.num2calc = Calculator()
result = calc(10, 20)
print(result)  # 结果为30

解释:

  • __call__ 方法描述符允许将 Calculator 类本身作为函数调用。
  • __call__ 方法中,self 参数表示 Calculator 对象,ab 参数表示方法参数。
  • 方法返回 Calculator 对象本身,以便可以继续使用其方法。

优点:

  • 简化了方法调用过程。
  • 允许将类作为函数使用。
  • 提高了代码可读性。

注意事项:

  • __call__ 方法描述符仅适用于类。
  • 如果 __call__ 方法描述符不正确定义,会导致错误。

实现缓存


在这个例子中,当我们尝试访问一个实例对象的属性时,__get__ 方法会被调用。如果实例对象没有该属性的缓存值,它会调用 self.func(instance) 来计算属性值,并将其缓存在实例对象上。

这种技术被称为"惰性计算"(lazy evaluation),它可以提高性能,因为属性值只有在第一次被访问时才会计算。之后,后续的访问都会直接返回缓存的值,而不需要再次计算。

下面是一个更具体的例子:

class LazyProperty:def __init__(self, func):self.func = funcself.cache_name = f"_{func.__name__}"def __get__(self, instance, owner):if instance is None:return selfif not hasattr(instance, self.cache_name):value = self.func(instance)setattr(instance, self.cache_name, value)return getattr(instance, self.cache_name)class Person:def __init__(self, name, age):self.name = nameself.age = age@LazyPropertydef full_name(self):print("Calculating full name...")return f"{self.name} Smith"person = Person("Alice", 30)
print(person.full_name)  # 输出: "Calculating full name..." 和 "Alice Smith"
print(person.full_name)  # 输出: "Alice Smith"

在这个例子中,我们定义了一个 LazyProperty 描述符类,它在第一次访问 full_name 属性时计算并缓存该值。后续访问都会直接返回缓存的值,而不需要再次计算。

总的来说,self.func(instance) 是描述符对象用来计算属性值的方法调用。通过使用描述符,我们可以自定义属性的访问行为,实现惰性计算等优化手段,提高代码的性能和可维护性。

相关文章:

Python 描述符

文章目录 类型&#xff1a;数据描述符&#xff1a;方法描述符&#xff1a;描述符的要包括以下几点:方法描述符实现缓存 描述符(Descriptor)是 Python 中一个非常强大的特性,它允许我们自定义属性的访问行为。使用描述符,我们可以创建一些特殊的属性,在访问这些属性时执行自定义…...

Go语言创建HTTP服务器

Web服务器可提供网页、Web服务和文件,而Go语言为创建Web服务器提供了强大的支持。 1.通过Hello World Web 服务器宣告您的存在 标准库中的net/http包提供了多种创建HTTP服务器的方法,它还提供了一个基本的路由器。 package mainimport ("net/http" )func helloWo…...

【LeetCode热题100】【栈】柱状图中最大的矩形

题目链接&#xff1a;84. 柱状图中最大的矩形 - 力扣&#xff08;LeetCode&#xff09; 要找最大的矩形就是要找以每根柱子为高度往两边延申的边界&#xff0c;要作为柱子的边界就必须高度不能低于该柱子&#xff0c;否则矩形无法同高&#xff0c;也就是需要找出以每根柱子为高…...

谷歌浏览器插件开发速成指南:弹窗

诸神缄默不语-个人CSDN博文目录 本文介绍谷歌浏览器插件开发的入门教程&#xff0c;阅读完本文后应该就能开发一个简单的“hello world”插件&#xff0c;效果是出现写有“Hello Extensions”的弹窗。 作为系列文章的第一篇&#xff0c;本文还希望读者阅读后能够简要了解在此基…...

Lakehouse 大数据概念

“Lakehouse” 是一个相对新的概念,是大数据理论中的一个重要发展方向。它试图结合传统的数据湖(Data Lake)和数据仓库(Data Warehouse)的优点,以创造一种更为灵活和强大的数据管理体系。 在传统的大数据架构中,数据湖用于存储原始、未加工的数据,而数据仓库则用于存储…...

MySQL学习笔记(二)

1、把查询结果中去除重复记录 2、连接查询 从一张表中单独查询&#xff0c;称为单表查询。emp表和dept表联合起来查询数据&#xff0c;从emp表中取员工名字&#xff0c;从dept表中取部门名字&#xff0c;这种跨表查询&#xff0c;多张表联合起来查询数据&#xff0c;被称为连…...

Verilog语法——按位取反“~“和位宽扩展的优先级

前言 先说结论&#xff0c;如下图所示&#xff0c;在Verilog中“~ ”按位取反的优先级是最高的&#xff0c;但是在等式计算时&#xff0c;有时候会遇到位宽扩展&#xff0c;此时需要注意的是位宽扩展的优先级高于“~”。 验证 仿真代码&#xff0c;下面代码验证的是“~”按位取…...

Navicat工具使用

Navicat的本质&#xff1a; 在创立连接时提前拥有了数据库用户名和密码 双击数据库时&#xff0c;相当于建立了一个链接关系 点击运行时&#xff0c;远程执行命令&#xff0c;就像在xshell上操作Linux服务器一样&#xff0c;将图像化操作转换成SQL语句去后台执行 一、打开Navi…...

linux常用指令(一)——mv、rm、which、find

mv命令&#xff1a; 用于查看文件内容 语法&#xff1a;mv 参数1 参数2 参数1&#xff0c;linux路径&#xff0c;表示被移动的文件或文件夹 参数2&#xff0c;linux路径&#xff0c;表示要移动去的地方&#xff0c;如果目标不存在&#xff0c;则进行改名 rm命令&#xff1a…...

lottery-攻防世界

题目 flag在这里要用钱买&#xff0c;这是个赌博网站。注册个账号&#xff0c;然后输入七位数字&#xff0c;中奖会得到相应奖励。 githacker获取网站源码 &#xff0c;但是找到了flag文件但是没用。 bp 抓包发现api.php&#xff0c;并且出现我们的输入数字。 根据题目给的附…...

深入理解指针2:数组名理解、一维数组传参本质、二级指针、指针数组和数组指针、函数中指针变量

目录 1、数组名理解 2、一维数组传参本质 3、二级指针 4、指针数组和数组指针 5、函数指针变量 1、数组名理解 首先来看一段代码&#xff1a; int main() {int arr[10] { 1,2,3,4,5,6,7,8,9,10 };printf("%d\n", sizeof(arr));return 0; } 输出的结果是&…...

【C/C++】C语言实现单链表

C语言实现单链表 简单描述代码运行结果 简单描述 用codeblocks编译通过 源码参考连接 https://gitee.com/IUuaena/data-structures-c.git 代码 common.h #ifndef COMMON_H_INCLUDED #define COMMON_H_INCLUDED#define ELEM_TYPE int //!< 链表元素类型/*! brief 返回值类…...

VBA数据库解决方案第九讲:把数据库的内容在工作表中显示

《VBA数据库解决方案》教程&#xff08;版权10090845&#xff09;是我推出的第二套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;是学完字典后的另一个专题讲解。数据库是数据处理的利器&#xff0c;教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…...

蓝桥杯刷题-12-公因数匹配-数论(分解质因数)不是很理解❓❓

蓝桥杯2023年第十四届省赛真题-公因数匹配 给定 n 个正整数 Ai&#xff0c;请找出两个数 i, j 使得 i < j 且 Ai 和 Aj 存在大于 1 的公因数。 如果存在多组 i, j&#xff0c;请输出 i 最小的那组。如果仍然存在多组 i, j&#xff0c;请输出 i 最小的所有方案中 j 最小的那…...

机器视觉学习(十二)—— 绘制图形

目录 一、绘制函数参数说明 1.1 cv2.line(&#xff09;绘制直线 1.2 cv2.rectangle&#xff08;&#xff09;绘制矩形 1.3 cv2.circle&#xff08;&#xff09; 绘制圆形 1.4 cv2.ellipse&#xff08;&#xff09;绘制椭圆 1.5 cv2.polylines&#xff08;&#xff09;绘制…...

软考信息处理技术员2024年5月报名流程及注意事项

2024年5月软考信息处理技术员报名入口&#xff1a; 中国计算机技术职业资格网&#xff08;http://www.ruankao.org.cn/&#xff09; 2024年软考报名时间暂未公布&#xff0c;考试时间上半年为5月25日到28日&#xff0c;下半年考试时间为11月9日到12日。不想错过考试最新消息的…...

linux:du和df区别

文章目录 1. 概述2. du 命令2. df 命令3. 区别总结 1. 概述 du 和 df 都是 Linux 系统中用于查看磁盘空间使用情况的命令&#xff0c;但它们的功能和用法有所不同。 2. du 命令 du 是 “disk usage” 的缩写&#xff0c;用于显示文件或目录的磁盘使用情况。du 命令用于查看指…...

MacOS Docker 部署 Redis 数据库

一、简介 Redis是一个开源的、使用C语言编写的、基于内存亦可持久化的Key-Value数据库&#xff0c;它提供了多种语言的API&#xff0c;并支持网络交互。Redis的数据存储在内存中&#xff0c;因此其读写速度非常快&#xff0c;每秒可以处理超过10万次读写操作&#xff0c;是已知…...

个推助力小米汽车APP实现智能用户触达,打造智能出行新体验

4月3日&#xff0c;小米SU7首批交付仪式在北京亦庄的小米汽车工厂总装车间举行&#xff0c;全国28城交付中心也同步开启首批交付。随着小米SU7系列汽车的正式发售和交付&#xff0c;小米汽车APP迎来了用户体量的爆发式增长。 小米汽车APP是小米汽车官方推出的手机应用&#xff…...

科研 | SCI、SCIE、ESCI、JIF、IF、IEEE Fellow

文章目录 SCISCIESCIE和SCI的区别SCIE和ESCI的区别JIF和IF有什么不同吗&#xff1f;IEEE Fellow SCI 科学引文索引&#xff08;Science Citation Index&#xff0c;SCI&#xff09;是由Clarivate Analytics&#xff08;原Thomson Reuters&#xff09;维护的一个重要的学术引文…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...

BLEU评分:机器翻译质量评估的黄金标准

BLEU评分&#xff1a;机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域&#xff0c;衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标&#xff0c;自2002年由IBM的Kishore Papineni等人提出以来&#xff0c;…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...

《Docker》架构

文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器&#xff0c;docker&#xff0c;镜像&#xff0c;k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...