python中的描述器

详解参见官方文档: https://docs.python.org/zh-cn/3/howto/descriptor.html
1. 如果一个类中定义了__get__(), set(), delete()三个方法中的任意一个, 那么这个类就是一个描述器
2. 非数据描述器
class A:
    def __get__(self, instance, owner):
        """
        :param instance: 调用方类的实例
        :param owner: 调用方的类
        """
        print(self, instance, owner)


class C:
# name一定得是类属性, 实例属性会失效
    name = A()


p = C()
print(p.name)
print(C.name)
# 结果如下:
<__main__.A object at 0x000001E025B0B320> <__main__.C object at 0x000001E025BDAA58> <class '__main__.C'>
None
<__main__.A object at 0x000001E025B0B320> None <class '__main__.C'>
None
3. 访问描述器对象的属性
class A:

    def __init__(self):
        self.cls_name = 'zs'

    def __get__(self, instance, owner):
        return self


class C:
    name = A()


p = C()
print(p.name.cls_name)
# 结果如下:
zs
4. 当实例属性覆盖同名的类属性指向的非数据描述器时
class A:

    def __init__(self):
        self.cls_name = 'zs'

    def __get__(self, instance, owner):
        return self


class C:
    name = A()

    def __init__(self):
        self.name = 'ls'


p = C()
print(p.name)
print(p.name.cls_name)
# 结果如下:
ls
AttributeError: 'str' object has no attribute 'cls_name'
5. 如果一个对象定义了__set__()或__delete__(),那么它就被认为是一个数据描述器。
class A:

    def __init__(self):
        self.cls_name = 'zs'

    def __get__(self, instance, owner):
        return self

    def __set__(self, instance, value):
        pass


class C:
    name = A()

    def __init__(self):
        self.name = 'ls'


p = C()
print(p.name)
print(p.name.cls_name)
# 结果如下:
# <__main__.A object at 0x000002629A57A470>
# zs
# 结论:实例对象访问属性时,数据描述器优先于实例对象的__dict__属性
6. 数据描述器__set__()的作用: 给描述器添加属性
class A:

    def __init__(self):
        self.cls_name = 'zs'

    def __get__(self, instance, owner):
        return self

    def __set__(self, instance, value):
        print('__set__()被调用了')
        self.age = value
        print(value)


class C:
    name = A()


p = C()
print(p.name.cls_name)
p.name = 18
# 结果如下:
# zs
# __set__()被调用了
# 18
7. 描述器的应用一
class A:

    def __init__(self):
        self.cls_name = 'zs'

    @property
    def get_name(self):
        return self.cls_name


a = A()
print(a.get_name)
# 结果如下:
通过属性的方法调用函数
8. 描述器应用二
class A:

    def __init__(self):
        self.__name = 'lw'

    def get_name(self):
        return self.__name

    def set_name(self, value):
        self.__name = value

    def delete_name(self):
        del self.__name

    name = property(fget=get_name, fset=set_name, fdel=delete_name)


a = A()
print(a.name)
a.name = 'ls'
print(a.name)
del a.name
print(a.name)

# 上下结果相同

class A:

    def __init__(self):
        self.__name = 'ww'

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, value):
        self.__name = value

    @name.deleter
    def name(self):
        del self.__name


a = A()
print(a.name)
a.name = 'ls'
print(a.name)
del a.name
print(a.name)
9. 手动实现property函数
class myproperty(object):
    '''自定义一个property'''

    def __init__(self, gfunc=None, sfunc=None, dfunc=None):
        self.gfunc = gfunc
        self.sfunc = sfunc
        self.dfunc = dfunc

    def __get__(self, instance, owner):
        return self.gfunc(instance)

    def setter(self, sfunc):
        self.sfunc = sfunc
        return self

    def __set__(self, instance, value):
        self.sfunc(instance, value)

    def deleter(self, dfunc):
        self.dfunc = dfunc
        return self

    def __delete__(self, instance):
        self.dfunc(instance)


class Zoo(object):
    '''动物园'''

    def __init__(self):
        self.animal_list = ['大象', '长颈鹿']

    def get_animal(self):
        '''获取所有的动物'''
        return self.animal_list

    def add_animal(self, value):
        '''添加动物'''
        self.animal_list.append(value)

    def pop_animal(self):
        '''删除最后一个动物'''
        self.animal_list.pop()

    animal = myproperty(gfunc=get_animal, sfunc=add_animal, dfunc=pop_animal)


zoo = Zoo()
print(zoo.animal)  # ['大象', '长颈鹿']
zoo.animal = '猪猪'
print(zoo.animal)  # ['大象', '长颈鹿', '猪猪']
del zoo.animal
print(zoo.animal)  # ['大象', '长颈鹿']
10. 使用描述器来实现一级缓存的目的
class CachedProperty(object):
    """缓存"""

    def __init__(self, func):
        self.func = func
        self.func_name = func.__name__

    def __get__(self, instance, owner):
        result = instance.__dict__[self.func_name] = self.func(instance)
        return result


class Person(object):

    @CachedProperty  # students = CachedProperty(students)
    def students(self):
        """
        计算过程非常复杂,同一个对象不论调用几次返回的结果都是一样的
        """
        print('数据库查询结果')
        return '使用缓存结果'


p = Person()
print(p.students)
print(p.students)
print(p.students)
# 结果如下:
数据库查询结果
使用缓存结果
使用缓存结果
使用缓存结果
结论: 以上实现一级缓存是利用了非数据描述器的"自己有同名属性就用自己的(自己.__dict__优先级大于描述器)", 我们在__get__()方法中添加了原来没有的属性并把它记录了下来, 在第一次访问时, 我们自己没有, 会用描述器的, 这样实现了优化访问的目的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值