十八.描述符(__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()

 

posted @ 2019-06-26 00:14  supreme9999  阅读(155)  评论(0编辑  收藏  举报