• 课时46:魔法方法:描述符(property的原理)


     目录:

      一、描述符(property的原理)

      二、课时46课后习题及答案

    **********************************

    一、描述符(property的原理)

    **********************************

    本节要讲的内容叫作描述符,用一句话解释,描述符就是将某种特殊类型的类的实例指派给另一个类的属性。那什么是特殊类型的类呢?就是至少要在这个类里边定义__get__()、__set__()或__delete__()三个特殊方法中的任意一个。

    下表列举了描述符相关的魔法方法:

    __get__(self, instance, owner)     用于访问属性,它返回属性的值
    __set__(self, instance, value)     将在属性分配操作中调用,不返回任何内容
    __delete__(self, instance)         控制删除操作,不返回任何内容

     举个直观的例子:

    class MyDescriptor:
        def __get__(self, instance, owner):
            print("getting...", self, instance, owner)
            
        def __set__(self, instance, value):
            print("setting...", self, instance, value)
            
        def __delete__(self, instance):
            print("deleting...", self, instance)
    
    class Test:
        x = MyDescriptor()

     由于MyDescriptor实现了__get__()、__set__()和__delete__()方法,并且将它的类实例指派给Test类的属性,所以MyDescriptor就是所谓描述符类。到这里,大家有没有看到property()的影子?

    好,实例化Test类,然后尝试着对x属性进行各种操作,看看描述符类会有怎样的响应:

    >>> test = Test()
    >>> test.x
    getting... <__main__.MyDescriptor object at 0x000001559C681CF8> <__main__.Test object at 0x000001559C67A588> <class '__main__.Test'>

    当访问x属性的时候,Python会自动调用描述符的__get__()方法,几个参数的内容分别是:self是描述符类自身的实例;instance是这个描述符的拥有者所在的类的实例,在这里也就是Test类的实例;owner是这个描述符的拥有者所在的类本身。

    >>> test.x = 'X-man'
    setting... <__main__.MyDescriptor object at 0x000001559C681CF8> <__main__.Test object at 0x000001559C67A588> X-man

    对x属性进行赋值操作的时候,Python会自动调用__set__()方法,前两个参数跟__get__()方法是一样的,最后一个参数value是等号右边的值。

    最后一个del操作也是同样的道理:

    >>> del test.x
    deleting... <__main__.MyDescriptor object at 0x000001559C681CF8> <__main__.Test object at 0x000001559C67A588>

    只要弄清楚描述符,那么property的秘密就不再是秘密了!property事实上就是一个描述符类。下边就定义一个属于我们自己的MyProperty:

    class MyProperty:
        def __init__(self, fget=None, fset=None, fdel=None):
            self.fget = fget
            self.fset = fset
            self.fdel = fdel
            
        def __get__(self, instance, owner):
            return self.fget(instance)
        
        def __set__(self, instance, value):
            self.fset(instance, value)
            
        def __delete__(self, instance):
            self.fdel(instance)
    
    class C:
        def __init__(self):
            self._x = None
            
        def getX(self):
            return self._x
        
        def setX(self, value):
            self._x = value
            
        def delX(self):
            del self._x
            
        x = MyProperty(getX, setX, delX)
    >>> c = C()
    >>> c.x = 'X-man'
    >>> c.x
    'X-man'
    >>> c._x
    'X-man'
    >>> del c.x
    >>> c.x
    Traceback (most recent call last):
      File "<pyshell#5>", line 1, in <module>
        c.x
      File "C:Users14158DesktopMyProperty.py", line 8, in __get__
        return self.fget(instance)
      File "C:Users14158DesktopMyProperty.py", line 21, in getX
        return self._x
    AttributeError: 'C' object has no attribute '_x'

    看,这不就实现了property()函数了嘛,简单吧?!

    最后讲一个实例:

    先定义一个温度类,然后定义两个描述符类用于描述摄氏度和华氏度两个属性。
    要求两个属性会自动进行转换,也就是说你可以给摄氏度这个属性赋值,然后打印的华氏度属性是自动转换后的结果。
    class Celsius:
        def __init__(self, value = 26.0):
            self.value = float(value)
    
        def __get__(self, instance, owner):
            return self.value
    
        def __set__(self, instance, value):
            self.value = float(value)
    
    class Fahrenheit:
        def __get__(self, instance, owner):
            return instance.cel * 1.8 + 32
    
        def __set__(self, instance, value):
            instance.cel = (float(value) - 32) / 1.8
    
    class Temperature:
        cel = Celsius()
        fah = Fahrenheit()
    >>> temp = Temperature()
    >>> temp.cel
    26.0
    >>> temp.fah
    78.80000000000001

    *******************************

    二、课时46课后习题及答案

    *******************************

  • 相关阅读:
    PL/pgSQL的RETURN QUERY例子
    PL/pgSQL的 RETURN NEXT例子
    PL/pgSQL学习笔记之二
    基于React的PC网站前端架构分析
    DialogFragment创建默认dialog
    一个RecycleView的强大adapter
    企业者的福音之8266接入阿里智能,点亮一盏灯。
    基于webmagic的种子网站爬取
    自上而下渐显图片的CSS3实现
    用SwiftGen管理UIImage等的String-based接口
  • 原文地址:https://www.cnblogs.com/DC0307/p/9535140.html
Copyright © 2020-2023  润新知