描述符__get__(),__set__(),__delete__()(三十七)

http://www.cnblogs.com/linhaifeng/articles/6204014.html#_label12

描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__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
View Code

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

#描述符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设置...
Int设置...
'''

# #描述符Str的使用
p1.name # Str调用
p1.name='zhangsan' # Str设置...
del p1.name # Str删除...
#
# #描述符Int的使用
p1.age # Int调用
p1.age=18 # Int设置...
del p1.age # Int删除...

# #我们来瞅瞅到底发生了什么
print(p1.__dict__) # {}
print(People.__dict__) # {'__weakref__': <attribute '__weakref__' of 'People' objects>,
                        # '__dict__': <attribute '__dict__' of 'People' objects>, '__doc__': None,
                        # '__init__': <function People.__init__ at 0x0000013E94AC5E18>, '__module__': '__main__',
            # 'name': <__main__.Str object at 0x0000013E94AD81D0>, 'age': <__main__.Int object at 0x0000013E94AD8198>}


# #补充
print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的 True
print(type(p1).__dict__ == People.__dict__) # True
View Code
#描述符Str
class Str:
    def __get__(self, instance, owner):
        print('Str调用')
    def __set__(self, instance, value):
        print('Str设置...')
        instance.__dict__['name'] = value
    def __delete__(self, instance):
        print('Str删除...')

#描述符Int
class Int:
    def __get__(self, instance, owner):
        print('Int调用')
    def __set__(self, instance, value):
        print('Int设置...')
        instance.__dict__['age'] = value
    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)
print(p1.__dict__) # {'name': 'alex', 'age': 18}
View Code

描述符分两种
一 数据描述符:至少实现了__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')

  注意事项:

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

#描述符Str
class Str:
    def __init__(self,key):
        self.key = key
    def __get__(self, instance, owner):
        print('Str调用')
        return instance.__dict__[self.key]
    def __set__(self, instance, value):
        print('Str设置...')
        if type(value) is not str:
            raise TypeError("类型错误")
        instance.__dict__[self.key] = value
    def __delete__(self, instance):
        print('Str删除...')
        instance.__dict__.pop(self.key)

#描述符Int
class Int:
    def __init__(self,key):
        self.key = key
    def __get__(self, instance, owner):
        print('Int调用')
        return instance.__dict__[self.key]
    def __set__(self, instance, value):
        print('Int设置...')
        if type(value) is not int:
            raise TypeError("请输入int型")
        instance.__dict__['age'] = value
    def __delete__(self, instance):
        print('Int删除...')
        instance.__dict__.pop(self.key)

class People:
    name=Str("name")
    age=Int("age")
    def __init__(self,name,age): #name被Str类代理,age被Int类代理,
        self.name=name
        self.age=age

p1=People("zhangsan",18)
print(p1.__dict__) # {'age': 18, 'name': 'zhangsan'}
print(p1.age)
del p1.age
print(p1.__dict__) # {'age': 18}

上面代码改进:

class Typed:
    def __init__(self,key, expected_type):
        self.key = key
        self.expected_type = expected_type
    def __get__(self, instance, owner):
        return instance.__dict__[self.key]
    def __set__(self, instance, value):
        if not isinstance(value, self.expected_type):
            raise TypeError("%s is not %s" %(value, self.expected_type))
        instance.__dict__[self.key] = value
    def __delete__(self, instance):
        instance.__dict__.pop(self.key)

class People:
    name=Typed("name", str)
    age=Typed("age", int)
    def __init__(self,name,age): #name被Str类代理,age被Int类代理,
        self.name=name
        self.age=age

#p1=People(99,18) # TypeError: 99 is not <class 'str'>
p1=People("zhangsan",'18') # TypeError: 18 is not <class 'int'>
原文地址:https://www.cnblogs.com/xiangtingshen/p/10463924.html