python关于描述符__set__ ,__get__ , __delete__

1.描述符

The following methods only apply when an instance of the class containing the method (a so-called descriptor class) appears in an owner class (the descriptor must be in either the owner’s class dictionary or in the class dictionary for one of its parents). In the examples below, “the attribute” refers to the attribute whose name is the key of the property in the owner class’ __ dict__.
下列方法只有在包含这些方法的类的实例出现在"所有者"类中(所有者的属性字典或者其父类的属性字典中)时才适用.

1)object.__ get__(self, instance, owner)
Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access). owner is always the owner class, while instance is the instance that the attribute was accessed through, or None when the attribute is accessed through the owner. This method should return the (computed) attribute value or raise an AttributeError exception.
当需要访问所有者类的属性或所有者类的实例的属性时被调用.其中参数owner就是所有者类, instance是要访问属性的实例,当所以者类访问属性时,该参数为None. 该方法应该返回属性值或抛出错误

2)object.__ set__(self, instance, value)
Called to set the attribute on an instance instance of the owner class to a new value, value.
调用以将所有者类的实例instance设置为一个新值value.

3)object.__ delete__(self, instance)
Called to delete the attribute on an instance instance of the owner class.
调用以删除所有者类的实例的属性

4)object.__ set_name__(self, owner, name)
Called at the time the owning class owner is created. The descriptor has been assigned to name.
当所有者类被创建时调用,描述符被赋值给name

1)描述符本质就是一个新式类, 在这个类中, 至少实现了 __ set__, __ get__,
__ delete__ 三种方法中的一种, 也被称为描述符协议.
__ get__ : 调用相关属性时触发;
__ set__ : 修改相关属性时触发;
__ delete__ : 删除相关属性时触发;
2)至少同时具有前两种方法的描述符称为数据描述符,
不具有__ set__ 方法的称为非数据描述符.
3)属性调用优先级: 类属性>数据描述符>实例属性>非数据描述符
4)描述符必须定义为类属性,不可放到函数中.
示例:

class Test:
    name = 'Testhahahaha'
    
       #self:描述符对象n, instance:实例t1, owner:t1所属的类Test1
    def __get__(self, instance, owner):  
        print('====>get')
        #print(self, instance, owner, sep='\n')
        return self

    def __set__(self, instance, value):    #value:值3
        print('====>set')
        #print(self.name, instance, value, sep='\n')
        instance.__dict__['n'] = value

    def __delete__(self, instance):
        print('====>delete')
        print(self, instance)


class Test1:
    n = Test()

    def __init__(self, name):
        self.name = name


#Test1.n = 'abc'   # 类属性的设置优先级高于描述符,不触发__set__
Test1.n             # 类调用属性会触发__get__
print('=====>hahaha')
t1 = Test1('sabi')  # 不涉及属性n时不会触发描述符
t1.n = 3            # 触发__set__, 增加属性n,但类属性不变
print(t1.__dict__)
print(t1.n)         # 触发__get__
del t1.n            # 触发__delete__
print('=====分隔')
del Test1.n         # 类删除属性也不会触发__delete__

#result
====>get
<__main__.Test object at 0x000001908F997470>
None
<class '__main__.Test1'>
=====>hahaha
====>set
{'name': 'sabi', 'n': 3}
====>get
<__main__.Test object at 0x000001908F997470>
<__main__.Test1 object at 0x000001908F997BA8>
<class '__main__.Test1'>
<__main__.Test object at 0x000001908F997470>
====>delete
<__main__.Test object at 0x000001908F997470> <__main__.Test1 object at 0x000001908F997BA8>
=====分隔

示例2: 非数据描述符,注意设置实例属性时描述符中也不能有delete方法,否则会报错

class Test:
    name = 'Testhahahaha'

    def __get__(self, instance, owner):
        print('====>get')
        print(self, instance, owner, sep='\n')
        return self
        
    # def __delete__(self, instance):
    #     print('====>delete')
    #     print(self, instance)

class Test1:
    n = Test()

    def __init__(self, name):
        self.name = name

t1 = Test1('sabi')
t1.n = 'niubi'        #没有set, 所以不会触发        
print(t1.__dict__)
print(t1.n)          #已经和描述符无关, 所以不会触发get        
del t1.n          
print(t1.__dict__)

#result
{'name': 'sabi', 'n': 'niubi'}
niubi
{'name': 'sabi'}

示例3: __ set_name__

class Test:
    name = 'Testhahahaha'

    def __get__(self, instance, owner):
        print('====>get')
        print(self, instance, owner, sep='\n')
        return self

    def __set_name__(self, owner, name):
        print('setname', owner, name, sep='\n')     

class Test1:
    n = Test()

    def __init__(self, name):
        self.name = name 

#result
setname
<class '__main__.Test1'>
n
2.描述符的应用

1)示例4: 输入类型限制,描述输入参数的类型

class Test1:

    def __init__(self, key, type):
        self.type = type
        self.key = key

    def __get__(self, instance, owner):
        print('get running')
        return instance.__dict__[self.key]  # 操作属性字典

    def __set__(self, instance, value):
        print('set running')
        if not isinstance(value, self.type):  # 同时限制多种类型
            raise TypeError('fuck wrong')
        instance.__dict__[self.key] = value

    def __delete__(self, instance):
        print('delete running')
        instance.__dict__.pop(self.key)


class Owner:

    name = Test1('name', str)
    age = Test1('age', int)
    weight = Test1('weight', float)

    def __init__(self, name, age, weight):
        self.name = name
        self.age = age
        self.weight = weight


t = Owner('sabi', 16, 123.5)
print(t.__dict__)
print(t.weight)
del t.age
print(t.__dict__)

#result
set running
set running
set running
{'name': 'sabi', 'age': 16, 'weight': 123.5}
get running
123.5
delete running
{'name': 'sabi', 'weight': 123.5}

2)示例5: 利用描述符自己定制property

class HahaProperty:
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        if instance is None:   # 当类调用时
            return self
        res = self.func(instance)
        instance.__dict__[self.func.__name__] = res  # 加入属性字典,避免重复运算
        return res


class Test:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    @HahaProperty
    def cal(self):
        return self.a + self.b

    @property
    def cal1(self):
        return self.a + self.b


t = Test('love', 'you')
print(t.cal,t.cal1)
print(Test.cal, Test.cal1)
print(Test.__dict__)
print(t.__dict__)

#result
loveyou loveyou
<__main__.HahaProperty object at 0x000001C646617CF8> <property object at 0x000001C646631C28>
{'__module__': '__main__', '__init__': <function Test.__init__ at 0x000001C646618EA0>, 'cal': <__main__.HahaProperty object at 0x000001C646617CF8>, 'cal1': <property object at 0x000001C646631C28>, '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None}
{'a': 'love', 'b': 'you', 'cal': 'loveyou'}

3.)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值