十八.描述符(__get__,__set__,__delete__)
描述符(__get__,__set__,__delete__)
4 注意事项: 一 描述符本身应该定义成新式类,被代理的类也应该是新式类 二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中 三 要严格遵循该优先级,优先级由高到底分别是 1.类属性 2.数据描述符 3.实例属性 4.非数据描述符 5.找不到的属性触发__getattr__()
1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__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 定义一个描述符
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 #疑问:何时,何地,会触发这
#描述符Str class Str: def __get__(self, instance, owner): print('Str调用') def __set__(self, instance, value): print('Str设置...') def __delete__(self, instance): print('Str删除...') #描述符Int class Int: def __get__(self, instance, owner): print('Int调用') def __set__(self, instance, value): print('Int设置...') def __delete__(self, instance): print('Int删除...') class People: name=Str() age=Int() def __init__(self,name,age): #name被Str类代理,age被Int类代理, self.name=name self.age=age #何地?:定义成另外一个类的类属性 #何时?:且看下列演示 p1=People('alex',18) #描述符Str的使用 p1.name p1.name='egon' del p1.name #描述符Int的使用 p1.age p1.age=18 del p1.age #我们来瞅瞅到底发生了什么 print(p1.__dict__) print(People.__dict__) #补充 print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的 print(type(p1).__dict__ == People.__dict__) # 描述符应用之何时?何地?三个方法的执行\ # 执行顺序 # Str设置... # Int设置... # Str调用 # Str设置... # Str删除... # Int调用 # Int设置... # Int删除... # {} # {'__module__': '__main__', 'name': <__main__.Str object at 0x00000177DAFD5048>, 'age': <__main__.Int object at 0x00000177DAFD5080>, '__init__': <function People.__init__ at 0x00000177DAFCAEA0>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None} # True # True
二 .描述符分两种
1. 数据描述符:至少实现了__get__()和__set__()
一 数据描述符:至少实现了__get__()和__set__() 1 class Foo: 2 def __set__(self, instance, value): 3 print('set') 4 def __get__(self, instance, owner): 5 print('get')
# 实例属性是低于 数据描述符 所以优先找的是描述符属性 优先级
class Foo:
def __set__(self, instance, value):
print('set')
print(value)
def __get__(self, instance, owner):
print('get')
print(owner)
class Per(object):
name=Foo()
def __init__(self,name):
self.name=name
def aa(self):
print(self.name)
f=Per("李四")
f.name
f.aa()
#
# get
# <class '__main__.Per'>
# get
# <class '__main__.Per'>
# None
2. 非数据描述符:没有实现__set__()
1 class Foo: 2 def __get__(self, instance, owner): 3 print('get')
# 实例属性是高于 非数据描述符 所以优先找的是实例属性 这就是优先级
class Foo:
def __get__(self, instance, owner):
print('get')
class Per(object):
name=Foo()
def __init__(self,name):
self.name=name
def aa(self):
print(self.name)
f=Per("李四")
print(f.name)
print(f.__dict__)
print(Per.__dict__)
# 李四
# {'name': '李四'}
# {'__module__': '__main__', 'name': <__main__.Foo object at 0x00000268526C8860>, '__init__': <function Per.__init__ at 0x00000268526CABF8>, 'aa': <function Per.aa at 0x00000268526CAD08>, '__dict__': <attribute '__dict__' of 'Per' objects>, '__weakref__': <attribute '__weakref__' of 'Per' objects>, '__doc__': None}
案例
众所周知,python是弱类型语言,即参数的赋值没有类型限制,下面我们通过描述符机制来实现类型限制功能 # 这是利用描述符来 来做 实例化属性 类型的判断 class Typed: def __init__(self,name,expected_type): self.name=name self.expected_type=expected_type def __get__(self, instance, owner): if instance is None: return self return instance.__dict__[self.name] def __set__(self, instance, value): if not isinstance(value,self.expected_type): raise TypeError('Expected %s' %str(self.expected_type)) instance.__dict__[self.name]=value def __delete__(self, instance): instance.__dict__.pop(self.name) # 这是利用描述符来 来做 实例化属性 类型的判断 class People: name=Typed('name',str) age=Typed('age',int) salary=Typed('salary',float) def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary def aa(self): print(self.name) p1=People('张三',18,3333.3) print(p1.__dict__) p1.aa()