也可参考,夏永锋  (Mastering   Python    Design  Patterns)  page 75

描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议

  • __get__():调用一个属性时,触发
  • __set__():为一个属性赋值时,触发
  • __delete__():采用del删除属性时,触发
class Foo: #在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符
def __get__(self, instance, owner):
pass
def __set__(self, instance, value):
pass
def __delete__(self, instance):
pass
class Foo: #在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符
def __get__(self, instance, owner):
pass
def __set__(self, instance, value):
pass
def __delete__(self, instance):
pass

2 描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)

class Foo:
def __get__(self, instance, owner):
print('触发get')
def __set__(self, instance, value):
print('触发set')
def __delete__(self, instance):
print('触发delete')
#包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法
f1=Foo()
f1.name='egon'
f1.name
del f1.name
#疑问:何时,何地,会触发这三个方法的执行
3 描述符分两种

一 数据描述符:至少实现了__get__()和__set__()

class Foo:

     def __set__(self, instance, value):
print('set')
def __get__(self, instance, owner):
print('get')

二 非数据描述符:没有实现__set__()

 class Foo:
def __get__(self, instance, owner):
print('get')

4 注意事项:
一 描述符本身应该定义成新式类,被代理的类也应该是新式类
二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
三 要严格遵循该优先级,优先级由高到底分别是
1.类属性
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()

#描述符Str
class Str:
def __get__(self, instance, owner):
print('Str调用')
def __set__(self, instance, value):
print('Str设置...')
def __delete__(self, instance):
print('Str删除...') class People:
name=Str()
def __init__(self,name,age): #name被Str类代理,age被Int类代理,
self.name=name
self.age=age

#基于上面的演示,我们已经知道,在一个类中定义描述符它就是一个类属性,存在于类的属性字典中,而不是实例的属性字典

#那既然描述符被定义成了一个类属性,直接通过类名也一定可以调用吧,没错
People.name #恩,调用类属性name,本质就是在调用描述符Str,触发了__get__()

People.name='egon' #那赋值呢,我去,并没有触发__set__()
del People.name #赶紧试试del,我去,也没有触发__delete__()
#结论:描述符对类没有作用-------->傻逼到家的结论 '''
原因:描述符在使用时被定义成另外一个类的类属性,因而类属性比二次加工的描述符伪装而来的类属性有更高的优先级
People.name #恩,调用类属性name,找不到就去找描述符伪装的类属性name,触发了__get__() People.name='egon' #那赋值呢,直接赋值了一个类属性,它拥有更高的优先级,相当于覆盖了描述符,肯定不会触发描述符的__set__()
del People.name #同上
'''
  

6 描述符总结

描述符是可以实现大部分python类特性中的底层魔法,包括@classmethod,@staticmethd,@property甚至是__slots__属性

描述父是很多高级库和框架的重要工具之一,描述符通常是使用到装饰器或者元类的大型框架中的一个组件.

7 利用描述符原理完成一个自定制@property,实现延迟计算(本质就是把一个函数属性利用装饰器原理做成一个描述符:类的属性字典中函数名为key,value为描述符类产生的对象)

class Lazyproperty:
def __init__(self,func):
self.func=func
def __get__(self, instance, owner):
print('这是我们自己定制的静态属性,r1.area实际是要执行r1.area()')
if instance is None:
return self
return self.func(instance) #此时你应该明白,到底是谁在为你做自动传递self的事情 class Room:
def __init__(self,name,width,length):
self.name=name
self.width=width
self.length=length @Lazyproperty #area=Lazyproperty(area) 相当于定义了一个类属性,即描述符
def area(self):
return self.width * self.length r1=Room('alex',1,1)
print(r1.area)

Lazyproperty

8 利用描述符原理完成一个自定制@classmethod

class ClassMethod:
def __init__(self,func):
self.func=func def __get__(self, instance, owner): #类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身,
def feedback():
print('在这里可以加功能啊...')
return self.func(owner)
return feedback class People:
name='linhaifeng'
@ClassMethod # say_hi=ClassMethod(say_hi)
def say_hi(cls):
print('你好啊,帅哥 %s' %cls.name) People.say_hi() p1=People()
p1.say_hi()
#疑问,类方法如果有参数呢,好说,好说 class ClassMethod:
def __init__(self,func):
self.func=func def __get__(self, instance, owner): #类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身,
def feedback(*args,**kwargs):
print('在这里可以加功能啊...')
return self.func(owner,*args,**kwargs)
return feedback class People:
name='linhaifeng'
@ClassMethod # say_hi=ClassMethod(say_hi)
def say_hi(cls,msg):
print('你好啊,帅哥 %s %s' %(cls.name,msg)) People.say_hi('你是那偷心的贼') p1=People()
p1.say_hi('你是那偷心的贼')

ClassMethod

9 利用描述符原理完成一个自定制的@staticmethod

class StaticMethod:
def __init__(self,func):
self.func=func def __get__(self, instance, owner): #类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身,
def feedback(*args,**kwargs):
print('在这里可以加功能啊...')
return self.func(*args,**kwargs)
return feedback class People:
@StaticMethod# say_hi=StaticMethod(say_hi)
def say_hi(x,y,z):
print('------>',x,y,z) People.say_hi(1,2,3) p1=People()
p1.say_hi(4,5,6)

StaticMethod

10.

class Typed:
def __init__(self,key,expected_type):
self.key=key
self.expected_type=expected_type
def __get__(self, instance, owner):
print('get方法')
# print('instance参数【%s】' %instance)
# print('owner参数【%s】' %owner)
return instance.__dict__[self.key]
def __set__(self, instance, value):
print('set方法')
# print('instance参数【%s】' % instance)
# print('value参数【%s】' % value)
# print('====>',self)
if not isinstance(value,self.expected_type):
# print('你传入的类型不是字符串,错误')
# return
raise TypeError('%s 传入的类型不是%s' %(self.key,self.expected_type))
instance.__dict__[self.key]=value
def __delete__(self, instance):
print('delete方法')
# print('instance参数【%s】' % instance)
instance.__dict__.pop(self.key) class People:
name=Typed('name',str) #t1.__set__() self.__set__()
age=Typed('age',int) #t1.__set__() self.__set__()
def __init__(self,name,age,salary):
self.name=name
self.age=age
self.salary=salary p1=People('alex',13,13.3)
print(p1.__dict__)
print(p1.name)
print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的
print(type(p1).__dict__ == People.__dict__)

描述符的应用

												

最新文章

  1. K近邻法(KNN)原理小结
  2. php基础_字符串
  3. LA 4287
  4. NOI2013 Day1
  5. Oracle语句优化规则(一)
  6. PHP基础语法思维导图
  7. 正益移动推出新产品正益工作 实现PaaS+SaaS新组合
  8. shell脚本判断安装包位置及类型
  9. JDBC测试计划-连接mysql
  10. java 中的Collection
  11. 【转】利用URLConnection来发送POST和GET请求
  12. Python Web学习笔记之TCP/IP、Http、Socket的区别
  13. DOS命令下使用sqlite3 命令中文乱码的解决办法
  14. 解决win10激活错误代码0xc004c003
  15. Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.elasticsearch.threadpool.ThreadPool
  16. 【BZOJ】2179: FFT快速傅立叶(fft)
  17. [LeetCode 题解]:Gas Station
  18. 安装MySQLdb for Python3.7
  19. 在ReactNative中使用Typescript
  20. sql的一些知识_函数_汇总数据

热门文章

  1. ELK学习笔记(一)安装Elasticsearch、Kibana、Logstash和X-Pack
  2. Android Service基础
  3. freemarker 类型转换
  4. 用SpringBoot搭建简单电商项目 01
  5. 和sin有关的代码
  6. java 中的JDK封装的数据结构和算法解析(集合类)----顺序表 List 之 ArrayList
  7. 凡事预则立(Beta)
  8. 201621123062《java程序设计》第13周作业总结
  9. django模型——数据库(二)
  10. Flask 学习 七 用户认证