python基础教程:属性查询顺序,数据描述符

嗨喽,大家好呀~这里是爱看美女的茜茜呐

数据描述符,属性查找优先级

如果在一个类中定义了 __get__() , __set__(), __delete__() 这三种方法之一,那么这个类是一个描述符。

描述符分成两种:

如果这种类只定义了 __get__ 方法,那么就是一个非数据描述符,
定义了__get__()和__set__()的数据描述符。

描述符的用处就是,当一个对象的某个属性是一个描述符时,你访问这个描述符类型的属性,就会调用这个描述符的方法。

譬如你获取描述符的值时,会调用它的__get__().

我们先看一下这三个方法的docstring:

def __delete__(self, *args, **kwargs): # real signature unknown""" Delete an attribute of instance. """# 删除一个实例的属性def __set__(self, *args, **kwargs): # real signature unknown""" Set an attribute of instance to value. """# 给实例的属性设置一个值def __get__(self, *args, **kwargs): # real signature unknown""" Return an attribute of instance, which is of type owner. """# 返回实例的属性,该实例是 `owner` 类型的

👇 👇 👇 更多精彩机密、教程,尽在下方,赶紧点击了解吧~

python源码、视频教程、插件安装教程、资料我都准备好了,直接在文末名片自取就可


实例:

class A(object):def __init__(self):self.value = Nonedef __set__(self, instance, value): # self:类A的实例,也是类B的属性a;instance:类 B 的实例 b;value:通过b.a的赋值print('set: self,instance,value',self,instance,value)self.value = valuereturn self.valuedef __get__(self, instance, owner):# instance:类B的实例b;owner:类Bprint('get: self,instance,owner',self,instance,owner)return self.valueclass B(object):a = A()def __init__(self):self.val = 20

1.上述代码中,有两个类,A,B。

先看类 B,有一个类属性 a , 且 a 是类 A 的实例,我们先来实例化一下类 B ,看一下 类 B 和实例 b 的属性:

b = B()
print(b.__dict__)
print(B.__dict__)"""
{'val': 20}{'__module__': '__main__', 'a': <__main__.A object at 0x0163FD70>, '__init__': <function B.__init__ at 0x07845078>, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None}
"""

可以看出,实例 b 的属性中,只有一个 val 属性 ;类 B 的属性中,则有一个 a ,且 a 是类 A 的一个对象。

2.接下来,我们调用一下实例 a:

b = B()
b.a
B.a"""
get: self,instance,owner <__main__.A object at 0x03458E68> <__main__.B object at 0x03458F28> <class '__main__.B'>get: self,instance,owner <__main__.A object at 0x03458E68> None <class '__main__.B'>
"""

我们看一下什么意思:

当调用 b.a 时,程序会自动去调用b.__getattribute__('a'), 也就是 b.__dict__['a'], 即通过对象 b 的字典去查找属性,但是在第一步我们已经知道, 对象 b 只有一个属性 {‘val’: 20} ,既然在实例 b 中找不到 a。

所以会去父类中找,调用:type(b).__dict__['a'].__get__(b,type(b)), 也就是: B.__dict__['a'].__get__(b,B),打印了第一行的信息,并返回了None

当调用 B.a 时,会直接调用 B.__dict__['a'].__get__(None,B),所以第二处打印的信息中间有个 None

3.现在,我们尝试给 b.a 赋值

b = B()
b.a = 11
print(b.__dict__)
print(B.__dict__)
B.a = 12
print(b.__dict__)
print(B.__dict__)"""
set: self,instance,value <__main__.A object at 0x037CFD70> <__main__.B object at 0x037CFDD0> 11
{'val': 20}{'__module__': '__main__', 'a': <__main__.A object at 0x037CFD70>, '__init__': <function B.__init__ at 0x07E85078>, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None}{'val': 20}{'__module__': '__main__', 'a': 12, '__init__': <function B.__init__ at 0x07E85078>, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None}
"""

可以看出,当调用了 b.a=11 时,调用了描述符的 set() , 但是对象 b 的实例属性并没有改变,依然只有 val=20, 同时类B的类属性也没有改变。 但是当调用 B.a = 12 时,类属性 a 变成了12,并没有调用描述符的__set__()方法。

所以,结合上面的 docstring,我们可以看出,数据描述符应该是给实例使用的,类使用它用处不大,至少没法调用它的 set()

如果类属性的描述符对象和实例对象的属性同名,如果查找?

也就是说,如果把类B改成:

class B(object):a = A()def __init__(self):self.val = 20self.a = 11  # 这里同名的属性

此时调用 b.a ,会如何?

当类A是一个数据描述符,也就是说类A包含 set 方法时,此时数据描述符优先级高,所以实例属性 self.a 其实就是对类属性 a 的赋值,会调用数据描述符的 set 方法:

set: self,instance,value <__main__.A object at 0x009DFD70> <__main__.B object at 0x009DFDD0> 11
get: self,instance,owner <__main__.A object at 0x009DFD70> <__main__.B object at 0x009DFDD0> <class '__main__.B'>
11

当类A是一个非数据描述符,那么实例的字典优先级高,所以会使用实例字典中的数据,即结果:

11

属性查询优先级:

  • obj.__getattribute__()

  • 数据描述符

  • 实例的字典

  • 类的字典

  • 非数据描述符

  • 父类的字典

  • __getattr__

class Quantity1(object):def __get__(self, instance, owner):return 2def __set__(self, instance, val):passclass Quantity2(object):def __get__(self, instance, owner):return 5class A(object):val = 6  # 6 父类属性x = Noneclass B(A):val = Quantity2()  # 5 非覆盖型描述符val = 4  # 4 类属性val = Quantity1()  # 2 覆盖型描述符def __init__(self):super(B, self).__init__()self.val = 3def __getattr__(self, name):  # 7 __getattr__return 7def __getattribute__(self, name):  # 1 __getattribute__return 1b = B()
print(b.val)

说了一堆有的没的,其实描述符就是一个特殊的实现,当你的一个对象的属性是描述符时,设置/赋值/读取 这个属性,都会触发这个描述符内部相应实现的方法。从而可以实现一些定制化的内容。

尾语

感谢你观看我的文章呐~本次航班到这里就结束啦 🛬

希望本篇文章有对你带来帮助 🎉,有学习到一点知识~

躲起来的星星🍥也在努力发光,你也要努力加油(让我们一起努力叭)。

最后,宣传一下呀~👇👇👇更多源码、资料、素材、解答、交流皆点击下方名片获取呀👇👇

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

核桃的数量---蓝桥杯

思路&#xff1a; 题目所代表的意思就是a,b,c这三个必须是核桃数量的因子&#xff0c;即a,b,c三个的最小公倍数 #include <iostream> #include <algorithm> using namespace std; // int main() { int a,b,c;cin>>a>>b>>c;int da*b/__gcd(a,b…

基于Django的计算机编程技术学习与服务平台

临近毕业&#xff0c;又到了赶毕设的时候了&#xff0c;本次介绍分享一下自己的毕业设计项目吧。 项目主题&#xff1a;基于Django的计算机技术编程技术学习与服务平台 实现功能&#xff1a; 1.登入&#xff1a;用户的登陆注册 2.Python教程&#xff1a;实现用户的Python技…

Vue3 emits 结合回调函数的使用

回调函数 先说下啥是回调函数&#xff0c;举个例子&#xff0c;当A方法调用B方法时&#xff0c;A方法会传一个方法作为参数给B方法&#xff0c;B方法中可以去按照逻辑执行A传递过的函数&#xff0c;就是回头再调用A方法传参给的方法。有点绕哈&#xff0c;写段代码参考下 con…

MacOS 无法ping 通 github.com 解决方案

ping github.com 会显示请求超时&#xff1a; PING github.com (192.30.253.112): 56 data bytes Request timeout for icmp_seq 0 Request timeout for icmp_seq 1 Request timeout for icmp_seq 2 Request timeout for icmp_seq 3 Request timeout for icmp_seq 4 Request …

无刷电机篇(一)直流无刷电机(BLDC)介绍

目录 01 直流无刷电机介绍 直流无刷电机内部结构 转子描述 定子描述 02 直流无刷电机分类 直流无刷电机分类描述 内、外转子电机描述 内、外转子电机区别 03 直流无刷电机参数 无刷电机参数 04 文章总结 大家好&#xff0c;这里是程序员杰克。一名平平无奇的嵌入式软…

PCL 高斯投影正算:大地坐标转高斯投影坐标(C++详细过程版)

目录 一、算法原理二、代码实现三、结果展示四、测试数据PCL 高斯投影正算:大地坐标转高斯投影坐标(C++详细过程版)由CSDN点云侠原创。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 二、代码实现 头文件及读取保存函数见:

记事本(父页面与iframe子页面的联通,vue3+ts展示fbx模型,与tga贴图)

vue3ts 展示fbx与tga贴图 npm i three --save <template><div ref"modelContainer"></div> </template><script setup lang"ts"> import { ref, onMounted } from vue; import * as THREE from three; import { FBXLoader…

深度学习基础之数据操作

深度学习中最常用的数据是张量&#xff0c;对张量进行操作是进行深度学习的基础。以下是对张量进行的一些操作&#xff1a; 首先我们需要先导入相关的张量库torch。 元素构造&#xff08;初始化&#xff09; 使用arange创造一个行向量&#xff0c;也就是0轴&#xff08;0维&a…

python学习笔记11(程序跳转语句、空语句)

&#xff08;一&#xff09;程序跳转语句 1、break 用法&#xff1a;循环语句中使用&#xff0c;结束本层循环&#xff0c;一般搭配if来使用。注意while/else语法 示例&#xff1a; i0; while i<3:user_nameinput(请输入用户名&#xff1a;)pwdinput("请输入密码&a…

arco design table遇到的一些问题

问题1:不知情就成了树形table table中不知道为啥就多了个树形加号在前面,查找问题后发现,是后端返回的数据中有children,框架中默认对这个参数做了树形结构。 解决办法: 当时没找到取消或者修改字段的属性或方法,就将此字段去掉,并将内容clone到childData。 问题2:c…

Java如何对OSS存储引擎的Bucket进行删除【OSS学习】

在前面学会了如何对OSS里面的Bucket进行创建&#xff1a;Java如何对OSS存储引擎的Bucket进行创建-CSDN博客 接下来&#xff0c;记录一下如何删除Bucket存储空间 目录 1、看看OSS&#xff1a; 2、代码&#xff1a; 3、运行效果&#xff1a; 1、看看OSS&#xff1a; 我准备将…

opencv009 滤波器01(卷积)

图像卷积操作&#xff08;convolution&#xff09;&#xff0c;或称为核操作&#xff08;kernel&#xff09;&#xff0c;是进行图像处理的一种常用手段&#xff0c; 图像卷积操作的目的是利用像素点和其邻域像素之前的空间关系&#xff0c;通过加权求和的操作&#xff0c;实现…

什么是中间人攻击? ssh 连接出现 Host key verification failed 解决方法

文章目录 前言known_hosts 文件是什么文件路径示例 连接出现 Host key verification failedssh-keygen -R [hostname or ip address]删除整个 known_hosts 文件 其它聊聊中间人攻击ssh 如何保证安全&#xff1f;加密流程漏洞在哪里如何避免中间人攻击 个人简介 前言 最近服务器…

可pin to pin替代TI DRV8872的GLOBALCHIP直流电机驱动芯片GC8872,低成本、宽电压,内置电荷泵,短地短电源保护,限流

在现如今电机驱动芯片处于持续涨价的状态下&#xff0c;并且供货期货期长&#xff0c;偶尔缺货的状态下。为了降低设计成本&#xff0c;第一时间设计出优秀的产品占据市场高位。我这边推荐使用浙江GLOBALCHIP国产电机驱动芯片进行替换设计。供货稳定、价格低廉。GC8872是GLOBAL…

使用uniApp+vue3+Vite4+pinia+sass技术栈构建微信小程序

使用uniApp的cli模式安装&#xff0c;可以使用vscode开发。不用再单独去下载HBuilderX. 1.基础安装 vue3tsuniapp 方法一&#xff1a; npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project方法二&#xff1a;可以去uni-preset-vue的vite分支下选择vite-ts直接下载zi…

win7虚拟机安装VMware Tools失败,主机远程虚拟机解决

情况描述:安装完win732位虚拟机后,VMWare Tools安装失败,这时传文件就成了问题;所以才有了此文档,需要通过主机直接远程到虚拟机进行文件传输,网上的说明不全,导致摸索了一番才解决此问题; 首先,下载win732补丁; 下载地址:Microsoft Update Catalog首先,虚拟机需要…

【数据结构】 链队列的基本操作 (C语言版)

目录 一、链队列 1、链栈的定义&#xff1a; 2、链栈的优缺点&#xff1a; 二、链队列的基本操作算法&#xff08;C语言&#xff09; 1、宏定义 2、创建结构体 3、链栈的初始化 4、链队列的入队 5、链队列的出队 6、取链队列的对头元素 7、链队列的销毁 8、链…

Windows Defender存在威胁执行操作无反应且一直存在红叉(已解决)

文章目录 前言问题如图一、原因二、解决办法&#xff08;亲试有效&#xff09;总结 前言 Windows安全中心&#xff08;Windows Defender&#xff09;执行快速扫描/完全扫描后一直存在威胁&#xff0c;执行隔离或者删除操作后下次扫描还会扫出该威胁&#xff0c;但看威胁文件位置…

一些es的基本操作

目录 给索引增加字段&#xff1a;给索引删除字段[^1]&#xff1a;创建索引&#xff1a;插入document删除document(应该是按ID) : 给索引增加字段&#xff1a; 用postMan: 给名为population_portrait_hash_seven的索引增加了一个text类型的字段。 用chrome插件Elasticvue 的Re…

架构管理敏捷常用工具

产品部署&#xff1a;Jenkins/云效流水线 代码库&#xff1a;Git 产品管理&#xff1a;Maven 任务进度管理&#xff1a;Jira/云效 API管理&#xff1a;SmartdocTorna-接口规范和接口发布 代码review&#xff1a;sornor做代码review 生产事故和BUG管理&#xff1a;阐道/云效-bug…