1.描述器的表现

用到三个魔术方法,__get__(), __set__(), __delete__()
方法签名如下
object.__get__(self,instance,owner)
object.__set__(self,instance,value)
object.__delete(self,instance)
self指代当前实例,调用者
instance是owner的实例
owner是属性的所输的类
#描述器A调用并赋值给了类B的属性,当调用类B或者实例b时,去类A执行__get__()函数,类调用instance返回none,实例调用返回实例
#执行顺序和类,实例字典无关
class A:
def __init__(self):
print(2,'A init')
def __set__(self, instance, value):
print(3,self,instance,value)
def __get__(self, instance, owner): #return值,将会影响b.x or B.x的调用属性
print(4,self,instance,owner) class B:
x = A()
def __init__(self):
print(1,'B init') b = B() #output 2->1
b.x #output 4 <__main__.A object at 0x047B09D0> <__main__.B object at 0x047BB350> <class '__main__.B'>
B.x #output 4 <__main__.A object at 0x047B09D0> None <class '__main__.B'> 此时访问b.x.a1 B.x.a1都会报错 AttributeError:Nonetype
问题出在__get__的返回值,修改为 return self 返回A的实例就具备了a1属性 返回正常
class B:
x = A()
def __init__(self):
self.b1 = A()
print(1,'B init') b = B() #output 2->1
print(b.b1) #output <__main__.A object at 0x03000990> 没有触发__get__的打印
从运行结果可以看出,只有类属性是类的实例才行

2.描述其的定义

python中,一个类实现了__get__,__set__.__delete__的三个方法中的任意一个就是描述器
1.如果仅仅实现了__get__.就是非数据描述器 non-data descriptor
2.同时实现了__get__,__set__,就是数据描述器,data descriptor
如果一个类的类属性,设置为描述器,那么这个类被称为owner属主,method也是类的属性
class A:
def __init__(self):
self.a1 = 'a1'
print(2,'A init') def __get__(self, instance, owner):
print(4,self,instance,owner)
return self class B:
x = A()
def __init__(self):
self.x = 'b1' #如果描述器定义了__set__,此时b1就是value
print(1,'B init') b = B() #output 2->1
print(B.x) #output 4 <__main__.A object at 0x04EEB350> None <class '__main__.B'> ;;;; return <__main__.A object at 0x02E8B350>
print(B.x.a1) #output 4 <__main__.A object at 0x02E8B350> None <class '__main__.B'> ;;;;return a1
print(b.x) #return b1 访问到了实例的属性,而不是描述器
print(b.x.a1) #AttributeError 'str object has no Attribute
在非数据描述器中,owner实例的属性 会被实例调用,而不是访问__get__描述器
#添加了set方法 对比上个代码,;数据描述器
class A:
def __init__(self):
self.a1 = 'a1'
print(2,'A init')
def __set__(self, instance, value): #当定义了set魔术方法后,B实例定义的实例属性self.x = 'b1 不会在写进实例字典,而是调用set方法
print(3,self,instance,value)
# instance.__dict__['x']=value
def __get__(self, instance, owner): #return值,将会影响b.x or B.x的调用属性
print(4,self,instance,owner)
# return instance.__dict__['x']
return self
class B:
x = A()
def __init__(self):
print(1,'B init')
print("+++++++++++++++++++++++")
self.x = 'b1'
print("+++++++++++++++++++++++") b = B() #output 2->1->+ ->3-> + ;;实例化时候,self.x = 'b1'调用了set方法
print(b.x.a1) #return a1 直接调用get
b.x = 100 #return a1 直接调用set
print(b.__dict__) #实例字典为空
print(B.__dict__)

总结:实例的__dict__优先于非数据描述器;;;数据描述器优先于实例__dict__

2.1描述器查找顺序和__dict__的关系

class A:
def __init__(self):
self.a1 = 'a1'
print(2,'A init')
def __set__(self, instance, value):
print(3,self,instance,value)
self.data = value
print(self.data)
def __get__(self, instance, owner):
print(4,self,instance,owner)
return self
class B:
x = A()
def __init__(self):
print(1,'B init')
self.x = 'b.x'
self.y = 'b.y'
self.z = 'b.z' b = B() #output 2->1->+ ->3-> + ;;实例化时候,self.x = 'b1'调用了set方法
print(b.y) #return b.y
print(b.x)
print(B.__dict__)
print(b.__dict__)#output {'y': 'b.y', 'z': 'b.z'} ;;;self.x 这里的x是x = A()所以调用set方法,而self.y self.z追加到字典

2.3练习

from functools import  partial
class StaticMethod:
def __init__(self,fn):
self.fn = fn
def __get__(self, instance, owner):
return self.fn
class ClassMethod:
def __init__(self,fn):
self.fn = fn
def __get__(self, instance, owner):
# return self.fn(instance)
return partial(self.fn,instance)
class Test:
@StaticMethod #st = staticmethod(st) 去调用__get__方法时,不用在考虑这个Test类了 装饰器到描述器执行,调用时加()就返回值
def st(): #st = return self.fn
print('st')
@ClassMethod
def ct(cls): #ct = return self.fn(instance)
print('ct')
t = Test()
Test.st()
t.st()
t.ct()
Test.ct()
class Typed:
def __init__(self,name,type):
self.name = name
self.type = type def __set__(self, instance, value):
if not isinstance(value,self.type):
raise TypeError(value)
instance.__dict__[self.name]=value def __get__(self, instance, owner):
if instance is not None:
return instance.__dict__[self.name]
return self
class Person:
name = Typed('name',str) # 1 演变其他的基础
age = Typed('age',int)
def __init__(self,name:str,age:int):
self.name = name #
self.age = age p = Person('tom',21)
print(p.__dict__) #output {'name': 'tom', 'age': 21}
print(p.age) #output 21
print(Person.age.name) #output age
print(Person.name.name) #output name
print(Typed.__dict__)
print(Person.__dict__)
# 1-->类属性调用了类实例,2-->有set,此处调用set方法,因为数据描述器,所以字典为空,自己追加字典值,
#get也需要从字典中获取值
import inspect
class Typed:
def __init__(self,name,type):
self.name = name
self.type = type def __set__(self, instance, value):
if not isinstance(value,self.type):
raise TypeError(value)
instance.__dict__[self.name]=value def __get__(self, instance, owner):
if instance is not None:
return instance.__dict__[self.name]
return self def typeassert(cls):
parmas = inspect.signature(cls).parameters
for k,v in parmas.items():
if v.annotation != v.empty:
setattr(cls,k,Typed(v,v.annotation))
return cls
@typeassert
class Person:
def __init__(self,name:str,age:int):
self.name = name #
self.age = age p = Person('tom',21)

Python之描述器的更多相关文章

  1. Python 黑魔法 --- 描述器(descriptor)

    Python 黑魔法---描述器(descriptor) Python黑魔法,前面已经介绍了两个魔法,装饰器和迭代器,通常还有个生成器.生成器固然也是一个很优雅的魔法.生成器更像是函数的行为.而连接类 ...

  2. python 简单了解一下 描述器

    1.描述器是什么? 在Python中描述器也被称为描述符, 1)描述器实际上是任何新式类(新式类是继承自 type 或者 object 的类),这种类至少实现了3个特殊的方法__get__, __se ...

  3. python cookbook第三版学习笔记十三:类和对象(三)描述器

    __get__以及__set__:假设T是一个类,t是他的实例,d是它的一个描述器属性.读取属性的时候T.d返回的是d.__get__(None,T),t.d返回的是d.__get__(t,T).说法 ...

  4. Python 面向对象(五) 描述器

    使用到了__get__,__set__,__delete__中的任何一种方法的类就是描述器 描述器的定义 一个类实现了__get__,__set__,__delete__中任意一个,这个类就是描述器. ...

  5. python类:描述器Descriptors和元类MetaClasses

    http://blog.csdn.net/pipisorry/article/details/50444769 描述器(Descriptors) 描述器决定了对象属性是如何被访问的.描述器的作用是定制 ...

  6. python描述器

    描述器定义 python中,一个类实现了__get__,__set__,__delete__,三个方法中的任何一个方法就是描述器,仅实现__get__方法就是非数据描述器,同时实现__get__,__ ...

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

    原文:https://zhuanlan.zhihu.com/p/32764345 https://www.cnblogs.com/aademeng/articles/7262645.html----- ...

  8. Python描述器引导(转)

    原文:http://pyzh.readthedocs.io/en/latest/Descriptor-HOW-TO-Guide.html 1. Python描述器引导(翻译) 作者: Raymond ...

  9. Python入门之面向对象编程(四)Python描述器详解

    本文分为如下部分 引言——用@property批量使用的例子来引出描述器的功能 描述器的基本理论及简单实例 描述器的调用机制 描述器的细节 实例方法.静态方法和类方法的描述器原理 property装饰 ...

随机推荐

  1. CloudStack+KVM环境搭建(步骤很详细,说明ClockStack是用来管理虚拟机的)

    文章目录环境准备配置本地域名解析关闭selinux安装ntp服务安装管理端安装Mysql数据库安装服务端RPM:初始化CloudStack数据库:初始化cloudstack管理服务器安装系统虚拟机安装 ...

  2. threadPoolExecutor的基本解析

    线程池的构造方法中常见参数简介 corepoolsize:核心线程数,即便这里的线程处于空闲状态,也不会被回收,会一直存在线程池中 maxmumpoolsize:线程池所能容纳的最大线程数,超过这个数 ...

  3. java Web开发基础(一)工程项目文档结构

    2013年毕业后,在深圳工作开始是用.NET ASP.NET MVC做的项目,后来公司用java来做.于是就从.NET转java了.从.NET转java不是那么的难.今天刚好是清明节放假三天,整理了j ...

  4. c语言指针应用

    指针变量指向数组元素: #import <stdio.h> int main() { int a[10]={1,2,3,4,5,6,7,8,9,0}; int *p; p=a; for ( ...

  5. 【托业】【新东方全真模拟】01~02-----P5~6

    12.precisely precise precision preciseness 114. 116. favorable adj.赞同的; 称赞的; 有利的; 讨人喜欢的; favor n.好感; ...

  6. 【前端技术】web 开发常见问题--GET POST 区别

    web 开发常见问题--GET POST 区别   首先,get和post是什么? --两种 HTTP 请求方法:GET 和 POST HTTP Request Methods GET.POST 专业 ...

  7. HBase 的MOB压缩分区策略介绍

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/zNZQhb07Nr/article/details/79832392 HBase应用场景很广泛.社区 ...

  8. 萌新接触前端的第三课——JavaScript

    JavaScript概述 一.JavaScript的历史 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中).后将其改名ScriptEase ...

  9. MySQL无损复制(转)

    MySQL5.7新特性:lossless replication 无损复制 https://dev.mysql.com/doc/refman/5.7/en/replication-semisync.h ...

  10. ELKStack的基础入门和中文指南

    一.ELKStack的中文指南 redhat系列配置repo源 rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch vi / ...