python的黑魔法

描述符

官方定义:python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问。这些方法有 get(), set(), 和delete()。如果这些方法中的任何一个被定义在一个对象中,这个对象就是一个描述符。简单地说: 某个类,只要是内部定义了方法 __get__, __set__, __delete__ 中的一个或多个,就可以称为描述符

但是描述符有什么作用呢

描述符的作用是用来代理一个类的属性。 描述符单独存在没有意义,一般描述符就是某个实例的属性,当访问该属性时,就会调用描述符的__get__方法,而修改会调用__set__方法,删除会调用__delete__方法;

首先定义一个描述符

class Descriptors:

def __init__(self, key):

self.name = key

def __get__(self, instance, owner):

print("执行Descriptors的get")

if instance:

return instance.__dict__['name']

return self.name

def __set__(self, instance, value):

print("执行Descriptors的set")

if not isinstance(value, str):

raise TypeError("名字必须为字符串")

if instance:

instance.__dict__['name'] = value

else:

self.name = value

class User():

name = '小明'

def __init__(self, name):

self.name = name

首先看一下类属性

User.name

'小明'

然后看一下实例属性

u1 = User(11)

u1.name,User.name

(11, '小明')

可以看到类属性与实例属性互不干扰,然后再看看使用描述符会怎么样

class User():

name = Descriptors('小明')

def __init__(self, name):

self.name = name

看一下类属性

User.name

执行Descriptors的get

'小明'

u1 = User(11)

执行Descriptors的set

---------------------------------------------------------------------------

TypeError Traceback (most recent call last)

in

----> 1 u1 = User(11)

in __init__(self, name)

2 name = Descriptors('小明')

3 def __init__(self, name):

----> 4 self.name = name

in __set__(self, instance, value)

12 print("执行Descriptors的set")

13 if not isinstance(value, str):

---> 14 raise TypeError("名字必须为字符串")

15 if instance:

16 instance.__dict__['name'] = value

TypeError: 名字必须为字符串

u1 = User('小王')

执行Descriptors的set

u1.name,User.name

执行Descriptors的get

执行Descriptors的get

('小王', '小李')

User.name=Descriptors('小李')

u1.name,User.name

执行Descriptors的get

执行Descriptors的get

('小王', '小李')

u2 = User('小明')

执行Descriptors的set

u1.name,User.name, u2.name

执行Descriptors的get

执行Descriptors的get

执行Descriptors的get

('小王', '小李', '小明')

可以看到虽然类属性与实例属性互不干扰,但是实例属性会调用类属性的魔法方法,前提是属性名字必须与描述符同名

所以可以通过描述符限定实例属性,对实例属性进行某些操作。感觉和装饰器很像

实现描述符的功能还有另一种方式,那就是装饰器

class User():

def __init__(self, x):

self.name = x

@property

def name(self):

return self.x

@name.setter

def name(self, value):

if not isinstance(value, str):

raise TypeError("名字必须为字符串")

self.x = value

u1 = User(11)

---------------------------------------------------------------------------

TypeError Traceback (most recent call last)

in

----> 1 u1 = User(11)

in __init__(self, x)

1 class User():

2 def __init__(self, x):

----> 3 self.name = x

4 @property

5 def name(self):

in name(self, value)

8 def name(self, value):

9 if not isinstance(value, str):

---> 10 raise TypeError("名字必须为字符串")

11 self.x = value

TypeError: 名字必须为字符串

u1 = User('小王')

u1.name

'小王'

这种方法其实底层也是通过描述符实现的,而且描述符比这种方法适应性更大。

描述符的分类

描述符分两种: + 数据描述符:实现了__get__ 和 __set__ 两种方法的描述符 + 非数据描述符:只实现了__get__ 一种方法的描述符 当我们对一个实例属性进行访问时,Python 会按 obj.dict → type(obj).dict → type(obj)的父类.dict 顺序进行查找,但是引入描述符之后,会改变这个搜索过程《流畅的Python》中写到,“Python存取属性的方式特别不对等,通过实例读取属性时,通常返回的是实例中定义的属性;但是,如果实例中没有指定的属性,那么会获取类属性。而为实例中的属性赋值时,通常会在实例中创建属性,根本不影响类。这种 不对等的处理方式对描述符也有影响。”

class Age:

def __init__(self, key):

self.age = key

def __get__(self, instance, owner):

print("执行Age的get")

if instance:

return instance.__dict__['age']

return self.age

def __set__(self, instance, value):

print("执行Age的set")

if not isinstance(value, int):

raise TypeError("年纪必须为整型")

if value<=0:

raise TypeError("年纪必须大于1")

if instance:

instance.__dict__['age'] = value

else:

self.age = value

class Nick:

def __init__(self, key):

self.nick = key

def __get__(self, instance, owner):

print("执行Nick的get")

if instance:

return instance.__dict__['nick']

return self.nick

class User():

name = Descriptors('小明')

age = Age(1)

nick = Nick('ming')

def __init__(self, name, age, nick):

self.name = name

self.age = age

self.nick = nick

u1 = User('小李', 10, 'sun')

执行Descriptors的set

执行Age的set

u1.age

执行Age的get

10

u1.nick

'sun'

因为Nick没有set的魔法方法,所以当实例中对nick属性赋值时,会直接在实例中赋值,所以这类查找的顺序是:实例的属性->找dict->找描述符,这些会更快一下如果实例字典中有与描述符同名的属性,如果描述符是数据描述符,优先使用数据描述符,如果是非数据描述符,优先使用字典中的属性。

python 描述符类_python的黑魔法--描述符相关推荐

  1. python编写ATM类_Python中编写类的各种技巧和方法

    有关 Python 内编写类的各种技巧和方法(构建和初始化.重载操作符.类描述.属性访问控制.自定义序列.反射机制.可调用对象.上下文管理.构建描述符对象.Pickling).你可以把它当作一个教程, ...

  2. python如何定义类_python中定义类

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 类的定义python中,定义类是通过class关键字,例如我们定义一个存储学生信 ...

  3. python如何定义类_Python 面向对象

    Python 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本章节我们将详细介绍Python的面向对象编程. 如果你以前没有接触过 ...

  4. python中定制类_python定制类__str__(实例详解)

    在接下来的文章中,让我们明白什么是python中的自定义类.学习什么是python的自定义类,python定制类可以扮演何种角色在python编程.当你看到像__xxx__ __slots__变量或函 ...

  5. python如何定义类_Python中类的定义、继承及使用对象实例详解

    本文实例讲述了Python中类的定义.继承及使用对象的方法.分享给大家供大家参考.具体分析如下: Python编程中类的概念可以比作是某种类型集合的描述,如"人类"可以被看作一个类 ...

  6. python查看所有异常类_Python调试常见异常汇总

    以下就是常见的异常以及其中文描述. BaseException --所有异常的基类 SystemExit --解释器请求退出 KeyboardInterrupt --用户中断执行(通常是输入^C) E ...

  7. python飞机大战类_Python版飞机大战

    前面学了java用java写了飞机大战这次学完python基础后写了个python版的飞机大战,有兴趣的可以看下. 父类是飞行物类是所有对象的父类,setting里面是需要加载的图片,你可以换称自己的 ...

  8. python模块和类_Python类、模块、包的区别

    类 类的概念在许多语言中出现,很容易理解.它将数据和操作进行封装,以便将来的复用. 模块 模块,在Python可理解为对应于一个文件.在创建了一个脚本文件后,定义了某些函数和变量.你在其他需要这些功能 ...

  9. python如何定义类_Python class定义类,Python类的定义(入门必读)

    在面向对象的程序设计过程中有两个重要概念:类(class)和对象(object,也被称为实例,instance),其中类是某一批对象的抽象,可以把类理解成某种概念:对象才是一个具体存在的实体.从这个意 ...

最新文章

  1. LabVIEW读写各类格式图像的方法(基础篇—1)
  2. ‘%.2f‘ 与 ‘{:.2f}‘.format(w) 区别
  3. Serendipity解决IE缓存为0
  4. android ImageButton显示本地图片
  5. java中doloop语句_Java中的do-while循环——通过示例学习Java编程(11)
  6. Manitest: Are classifiers really invariant?论文解读
  7. 没有实际的工作经验,如何面试Linux运维工程师?
  8. JS-获取当前URL的参数
  9. java过滤敏感词汇
  10. Python学习 Task01 :变量,运算符,与数据类型
  11. web服务器集群-------Apache网页优化 (1)网页压缩
  12. blos硬盘启动台式计算机,电脑如何bios设置硬盘启动顺序?掌握这6大类型是关键!...
  13. 【OCP】小麦苗OCP(包括11g、12c、18c、19c等)网络班早已开讲,注重实践,报名一次,终身可免费升级学习,推荐有红包...
  14. kali linux CC搭建教程,kali linux初次安装配置
  15. 产品经理之如何快速阐释产品价值(FABE模型)
  16. R语言GARCH-DCC模型和DCC(MVT)建模估计
  17. 李宏毅svm_【李宏毅机器学习笔记】 18、支持向量机(Support Vector Machine,SVM)...
  18. 关于zigbee的一些术语
  19. 华为2288H v5服务器配置JBOD(硬盘直通)
  20. 怎么制作微信gif表情?这几个方法简单好用

热门文章

  1. Maven学习总结(27)——Maven自定义打包插件maven-assembly-plugin详解
  2. Windows学习总结(15)——Notepad++ 快捷键大全
  3. 电信主机托管费用_电信服务器托管价格
  4. Muse-UI +Vue2.0框架开发环境搭建
  5. 安装 Android Studio 2.3 详细过程及错误解决
  6. 使用wampserver部署的织梦站点无法登录后台
  7. [工具类]文件或文件夹xx已存在,则重命名为xx(n)(2)
  8. 最大子矩阵问题悬线法 学习小结
  9. flutter: 根视图、根元素与根渲染
  10. windows下的workon env