python之 描述符(__get__,__set__,__delete__)

描述符(__get__,__set__,__delete__)

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调用')
        print(instance, owner)
    def __set__(self, instance, value):
        print('Str设置...')
        print(instance,value)
    def __delete__(self, instance):
        print('Str删除...')
        print(instance)


class People:
    name = Str()  # name 属性被代理,将这个类作用于另外一个类的属性来使用

    def __init__(self,name): #name被Str类代理
        self.name = name

p1 = People('long')

# 描述符Str的使用
p1.name
p1.name = 'sss'
del p1.name

print(p1.__dict__)
print(People.__dict__)

'''
结果:
Str设置...
<__main__.People object at 0x000001E6CA585C88> long
Str调用
<__main__.People object at 0x000001E6CA585C88> <class '__main__.People'>
Str设置...
<__main__.People object at 0x000001E6CA585C88> sss
Str删除...
<__main__.People object at 0x000001E6CA585C88>
{}
{'__module__': '__main__', 'name': <__main__.Str object at 0x000001E6CA585BE0>, '__init__': <function People.__init__ at 0x000001E6CA584048>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}


'''

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

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

5 描述符使用

众所周知,python是弱类型语言,即参数的赋值没有类型限制,下面我们通过描述符机制来实现类型限制功能

#描述符
class Typed:
    def __init__(self,key):
        self.key = key

    def __get__(self, instance, owner):
        print('get方法')
        # print('instance参数:%s'%instance) # People object
        # print('owner参数:%s'%owner)
        return instance.__dict__[self.key]

    def __set__(self, instance, value):
        # 代理的好处:可以对传进来的值进行下一步判断
        print('set方法')
        # print('instance参数:%s'%instance) # People Object
        # print('value参数:%s'%value)
        if not isinstance(value,str):
            raise TypeError('你传入的值不是字符类型')
        instance.__dict__[self.key] = value

    def __delete__(self, instance):
        print('delete方法')
        # print('instance参数:%s'%instance) # People object
        instance.__dict__.pop(self.key)

class People:
    name = Typed('name')  # 代理类
    def __init__(self,name,age,salary):
        self.name = name
        self.age = age
        self.salary = salary

p1 = People('asd',18,330)  # (数据描述符>实例)创建实例时,触发__set__
print(p1.__dict__)
print('-----------------')
p1.name = 'log'
print(p1.__dict__)
print('------------------')
name = p1.name
print(name)
print('------------------')
del p1.name
print(p1.__dict__)
'''
结果:
set方法
{'name': 'asd', 'age': 18, 'salary': 330}
-----------------
set方法
{'name': 'log', 'age': 18, 'salary': 330}
------------------
get方法
log
------------------
delete方法
{'age': 18, 'salary': 330}
'''

# -------------如果传入的name不是字符串类型-----------------
p2 = People(321,18,330)
'''
Traceback (most recent call last):
set方法
  File "F:/Python3/老男孩/面向对象/day4/描述符应用.py", line 60, in <module>
    p2 = People(321,18,330)
  File "F:/Python3/老男孩/面向对象/day4/描述符应用.py", line 29, in __init__
    self.name = name
  File "F:/Python3/老男孩/面向对象/day4/描述符应用.py", line 18, in __set__
    raise TypeError('你传入的值不是字符类型')
TypeError: 你传入的值不是字符类型
'''
#描述符
class Typed:
    def __init__(self,key,key_type):
        self.key = key
        self.key_type = key_type
    def __get__(self, instance, owner):
        print('get方法')
        # print('instance参数:%s'%instance) # People object
        # print('owner参数:%s'%owner)
        return instance.__dict__[self.key]

    def __set__(self, instance, value):
        # 代理的好处:可以对传进来的值进行下一步判断
        print('set方法')
        # print('instance参数:%s'%instance) # People Object
        # print('value参数:%s'%value)
        if not isinstance(value,self.key_type):
            raise TypeError('%s不是%s'%(value,self.key_type))

        instance.__dict__[self.key] = value

    def __delete__(self, instance):
        print('delete方法')
        # print('instance参数:%s'%instance) # People object
        instance.__dict__.pop(self.key)

class People:
    name = Typed('name',str)  # 代理类
    age = Typed('age',int)
    def __init__(self,name,age,salary):
        self.name = name
        self.age = age
        self.salary = salary


# ----------------------3 多个值进行判断-------------------
p1 = People('long','18',2000)
'''
Traceback (most recent call last):
set方法
  File "F:/Python3/老男孩/面向对象/day4/描述符应用.py", line 76, in <module>
set方法
    p1 = People('long','18',2000)
  File "F:/Python3/老男孩/面向对象/day4/描述符应用.py", line 32, in __init__
    self.age = age
  File "F:/Python3/老男孩/面向对象/day4/描述符应用.py", line 18, in __set__
    raise TypeError('%s不是%s'%(value,self.key_type))
TypeError: 18不是<class 'int'>
'''

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值