标签:代码 put ini ict main bsp art rip __init__
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练习
#StaticMethod from functools import partial class StaticMethod: def __init__(self,x): self.x = x def __get__(self, instance, owner): return self.x class ClassMethod: def __init__(self,x): self.x = x def __get__(self, instance, owner): return partial(self.x,owner) class A: @StaticMethod def a(): print("a") @ClassMethod #b = classmethod(b); def b(cls): print("b")
A().b()
A.b()
A.a()
A().a()
标签:代码 put ini ict main bsp art rip __init__
原文地址:https://www.cnblogs.com/harden13/p/9038872.html