python描述符详解

什么是描述符

官方的定义:描述符是一种具有“捆绑行为”的对象属性。访问(获取、设置和删除)它的属性时,实际是调用特殊的方法(_get_(),_set_(),_delete_())。也就是说,如果一个对象定义了这三种方法的任何一种,它就是一个描述符。

描述符的作用是用来代理一个类的属性,需要注意的是描述符不能定义在被使用类的构造函数中,只能定义为类的属性,它只属于类的,不属于实例,我们可以通过查看实例和类的字典来确认这一点。

描述符是实现大部分Python类特性中最底层的数据结构的实现手段,我们常使用的@classmethod@staticmethd@property、甚至是__slots__等属性都是通过描述符来实现的。它是很多高级库和框架的重要工具之一,是使用到装饰器或者元类的大型框架中的一个非常重要组件。

普通对象

示例

class Parent:
    name = "parent"

class Son(Parent):
    name = "son"

s = Son()
s.name = "other"
print(s.name)
------------------------------------------------------------------------
other

普通的python对象操作(增删改查)它的属性时,都是基于该对象的__dict__基础之上进行的。比如,上例中访问实例对象s的属性name: s.name的时候,查找顺序如下所示:

  1. 通过实例对象的__dict__属性访问: s.__dict__[‘name‘]
  2. 通过类型对象的__dict__属性访问: type(s).__dict__[‘name‘]等价于Son.__dict__[‘name‘]
  3. 通过父类对象的__dict__属性访问: s.__class__.__base__.__dict__[‘name‘]等价于Parent.__dict__[‘name‘]

类似地修改属性name的值也是通过__dict__的方式:

s.__dict__['name'] = 'zhangsan'
print s.name
------------------------------------------------------------------------
zhangsan

描述符

class Descriptor:
    def __init__(self, name):
        self.name = name

    def __get__(self, instance, owner):
        print("__get__")
        print("instance:", instance)
        print("owner:", owner)
        return self.name

    def __set__(self, instance, value):
        print("__set__", instance, value)
        self.name = value

class Man:
    name = Descriptor("张三")

someone = Man()
print(someone.name)
---------------------------------------------------------------------
__get__
instance: <__main__.Man object at 0x0000026B570D9E48>
owner: <class '__main__.Man'>
张三

这里的Descriptor就是一个描述符,访问Man对象的name属性时不再是通过__dict__属性来访问,而是通过调用Descriptor的__get__方法获取,同样的道理,给name赋值的时候是通过调用__set__方法实现而不是通过__dict__属性。

通过__dict__赋值,点号取值

someone.__dict__['name'] = '李四'
print(someone.name)
-----------------------------------------------------------------------
__get__
instance: <__main__.Man object at 0x0000026B570D9048>
owner: <class '__main__.Man'>
张三

通过点号赋值

someone.name = "王二"
print(someone.name)
------------------------------------------------------------------------
__set__ <__main__.Man object at 0x0000026B570D9D88> 王二
__get__
instance: <__main__.Man object at 0x0000026B570D9D88>
owner: <class '__main__.Man'>
王二

类似地,删除属性的值也是通过调用__delete__方法完成的。

数据描述符和非数据描述符

一个类,如果只定义了__get__ 方法,而没有定义__set__, __delete__ 方法,则认为是非数据描述符;反之,则成为数据描述符。
实例属性和类属性优先级高于非数据描述符,但低于数据描述符。

class Descriptor:
    def __init__(self, name):
        self.name = name

    def __get__(self, instance, owner):
        print("__get__")
        print("instance:", instance)
        print("owner:", owner)
        return self.name

class Man:
    name = Descriptor("张三")

m = Man()
# 实例属性
print("1:", m.name)
m.name = "李四"
print("2:", m.name)
print("3", Man.name)
Man.name = "王二"
print("4", Man.name)
-----------------------------------------------------------------------
__get__
instance: <__main__.Man object at 0x000001DDC4FDE1C8>
owner: <class '__main__.Man'>
1: 张三
2: 李四
__get__
instance: None
owner: <class '__main__.Man'>
3 张三
4 王二

属性查询优先级

  1. __getattribute__
  2. 数据描述符:由1触发调用,若人为的重载了该__getattribute__方法,可能会调职无法调用描述符
  3. 实例对象的字典
  4. 类的字典
  5. 非数据描述符
  6. 父类的字典
  7. __getattr__方法

原文地址:https://www.cnblogs.com/Raymon-Geng/p/11795976.html

时间: 2024-08-29 21:07:44

python描述符详解的相关文章

USB HID Report Descriptor 报告描述符详解

Report descriptors are composed of pieces of information. Each piece of information is called an Item.报告描述符由一些数据片组成.这些数据片被叫做Item.All items have a one-byte prefix that contains the item tag, item type, and item size. 每一个Item都包含一个字节的前缀,这个前缀中包含了三个信息--it

Python学习之属性访问与描述符详解

在Python开发中,对于一个对象的属性访问,我们一般采用的是点(.)属性运算符进行操作.例如,有一个类实例对象 foo ,它有一个 name 属性,那便可以使用 foo.name 对此属性进行访问.一般而言,点(.)属性运算符比较直观,也是我们经常碰到的一种属性访问方式.然而,在点(.)属性运算符的背后却是别有洞天,值得我们对对象的属性访问进行探讨. 在进行对象属性访问的分析之前,我们需要先了解一下对象怎么表示其属性.为了便于说明,本文以新式类为例.有关新式类和旧式类的区别,大家可以查看Pyt

【从头开始写操作系统系列】页表以及相关的描述符详解

在之前的文章中,我们介绍过 GDT(全局描述符表)以及一致代码段和非一致代码段,这篇文章我们再回到描述符,这次我们来以 ARM 架构为例了解一下页表描述符. 在这篇文章中,我们会看到以下内容: 页表是什么? 一级页表的地址变换过程 由一级描述符来获取二级描述符或者段地址的过程 页表 页表是什么? 页表是一种特殊的数据结构,放在系统空间的页表区,存放逻辑页与物理页帧的对应关系. 每一个进程都拥有一个自己的页表,PCB表中有指针指向页表. (来自百度百科) 通俗的来讲,页表的内容就是一个描述符(关于

usb命令格式、描述符详解

一.USB命令 在USB规范里,对命令一词提供的单词为“Request”,但这里为了更好的理解主机与设备之间的主从关系,将它定义成“命令”. 所有的USB设备都要求对主机发给自己的控制命令作出响应,USB规范定义了11个标准命令,它们分别是:Clear_Feature. Get_Configuration.Get_Descriptor.Get_Interface.Get_Status.Set_Address. Set_Configuration.Set_Descriptor.Set_Interf

(转)面向对象(深入)|python描述器详解

原文:https://zhuanlan.zhihu.com/p/32764345 # 类似函数的形式 class A: def __init__(self, name, score): self.name = name # 普通属性 self.score = score def getscore(self): return self._score def setscore(self, value): print('setting score here') if isinstance(value,

Python 字符串方法详解

Python 字符串方法详解 本文最初发表于赖勇浩(恋花蝶)的博客(http://blog.csdn.net/lanphaday),如蒙转载,敬请保留全文完整,切勿去除本声明和作者信息. 在编程中,几乎90% 以上的代码都是关于整数或字符串操作,所以与整数一样,Python 的字符串实现也使用了许多拿优化技术,使得字符串的性能达到极致.与 C++ 标准库(STL)中的 std::string 不同,python 字符串集合了许多字符串相关的算法,以方法成员的方式提供接口,使用起来非常方便. 字符

Python之print详解

Python之print详解 http://www.jb51.net/article/55768.htm print的一些基本用法,在前面的讲述中也涉及一些,本讲是在复习的基础上,尽量再多点内容. eval() 在print干事情之前,先看看这个东东.不是没有用,因为说不定某些时候要用到. 复制代码 代码如下: >>> help(eval)      #这个是一招鲜,凡是不理解怎么用,就用这个看文档 Help on built-in function eval in module __b

python之struct详解

python之struct详解 2018-05-23 18:20:29 醉小义 阅读数 20115更多 分类专栏: python 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_30638831/article/details/80421019 用处 按照指定格式将Python数据转换为字符串,该字符串为字节流,如网络传输时,不能传输int,此时先将int转化为字节流,然后再发送;

杂项之python描述符协议

杂项之python描述符协议 本节内容 由来 描述符协议概念 类的静态方法及类方法实现原理 类作为装饰器使用 1. 由来 闲来无事去看了看django中的内置分页方法,发现里面用到了类作为装饰器来使用,由于之前就看到过这一类的用法,但是一直没有明白具体是如何实现的,今天本着打破砂锅问到底的精神去网上搜资料,在这里不得不吐槽下百度搜索的垃圾了.....竞价排名做的那么6,搜一些技术文档.....各种坑爹...就是找不到想要的资源...于是FQ上google搜了搜,找到了python官网的文档...