• 33.描述器(二)


    (三十四)描述器二

     

    4:数据描述器

        # 示例1:
        class XKD1:
            def __init__(self):
                self.course = 'Python'
                print('XKD1.__init__')
            def __get__(self, instance, owner):
                # 这里的self为XKD1的实例. instance为实例, 如果是类访问,那么instance为None. owner是调用者的类
                print('self={} instance={} owner={}'.format(self, instance, owner))
                # todo: 返回XKD1的实例self
                return self
        class XKD2:
            x = XKD1()
            def __init__(self):
                print('XKD2.__init__')
                self.y = XKD1()   # 没有调用__get__方法
        print('*'*100)
        print(XKD2.x.course) # self=<__main__.XKD1 object at 0x108c39b38> instance=None owner=<class '__main__.XKD2'>
        print('*'*100)
        obj = XKD2()
        print('*'*100)
        print(obj.y)   # 返回 <__main__.XKD1 object at 0x103b56cf8>
        小结: 当非数据描述器是实例的变量时,实例访问非数据描述器不会调用__get__方法,只是访问了描述器类的实例
        # 示例2:数据描述器
        class XKD1:
            def __init__(self):
                self.course = 'Python'
                print('XKD1.__init__')
            def __get__(self, instance, owner):
                print('self={} instance={} owner={}'.format(self, instance, owner))
                return self
            def __set__(self, instance, value):
                print('self={} instance={} value={}'.format(self, instance, value))
                self.course = value
        class XKD2:
            x = XKD1()
            def __init__(self):
                print('XKD2.__init__')
                self.y = XKD1()   # 调用了__get__方法
        print('*'*100)
        print(XKD2.x.course)
        print('*'*100)
        obj = XKD2()
        print('*'*100)
        print(obj.x)
        小结: 当数据描述器是实例的变量时,实例访问数据描述器会调用描述器的__get__方法

    5:非数据描述器和数据描述器的访问顺序

        # 示例1:非数据描述器
        class XKD1:
            def __init__(self):
                self.course = 'Python'
                print('XKD1.__init__')
            def __get__(self, instance, owner):
                print('self={} instance={} owner={}'.format(self, instance, owner))
                return self
        class XKD2:
            x = XKD1()
            def __init__(self):
                print('XKD2.__init__')
                self.x = 'XKD1'          # 实例访问的是自己的__dict__中的x属性
        print('*'*100)
        print(XKD2.x.course)
        print('*'*100)
        obj = XKD2()
        print('*'*100)
        print(obj.x)  # 返回 'XKD1'
        # 示例2:数据描述器
        class XKD1:
            def __init__(self):
                self.course = 'Python'
                print('XKD1.__init__')
            def __get__(self, instance, owner):
                print('self={} instance={} owner={}'.format(self, instance, owner))
                return self
            def __set__(self, instance, value):
                print('self={} instance={} value={}'.format(self, instance, value))
                self.course = value
        class XKD2:
            x = XKD1()
            def __init__(self):
                print('XKD2.__init__')
                self.x = 'XKD1'          # 实例这里访问的是类属性x,也就是数据描述器,会调用数据描述器的__get__方法
        print('*'*100)
        print(XKD2.x.course)
        print('*'*100)
        obj = XKD2()
        print('*'*100)
        print(obj.x)  # 调用__get__方法,返回 XKD1实例
        小结: 一个类实例的查找属性顺序为:先查找类或父类中的数据描述器属性, 在查找自己__dict__中的属性,再查找类或父类的非数据描述器, 数据描述器优先于实例的__dict__, 实例的__dict__属性优先于非数据描述器, 当存在描述器的时候,属性的查找顺序为:类或父类的数据描述器属性 --> 实例的__dict__属性 --> 类或父类的非数据描述器属性

    4.数据描述器

    • 当非数据描述器是实例的变量时,实例访问非数据描述器不会调用__get__方法,只是访问了描述器类的实例;

    • 当数据描述器是实例的变量时,实例访问数据描述器会调用描述器的__get__方法;

    5.非数据描述器和数据描述器的访问顺序

    当存在描述器的时候,一个类实例的查找属性顺序为:先查找类或父类中是否有数据描述器属性,如果有那么,先访问数据描述器,如果没有数据描述器 --> 那么就会查找自己实例的__dict__属性,如果__dict__属性里面也没有找到 --> 就会在类或父类的非数据描述器中进行查找;

  • 相关阅读:
    每天学习一个设计模式(十二):创建型之单例模式
    每天学习一个设计模式(十一):创建型之原型模式
    每天学习一个设计模式(十):创建型之工厂方法模式
    每天学习一个设计模式(九):创建型之建造者模式
    数据库
    操作系统
    计算机网络
    Java 基础知识
    Linux基本操作
    git 基本操作
  • 原文地址:https://www.cnblogs.com/zhongguiyao/p/14873810.html
Copyright © 2020-2023  润新知