目录
__get__(self, instance, owner):
__set__(self, instance, value):
描述符(descriptor),就是将某种特殊类型的类的实例对象,赋另一个类的属性;
描述符方法,包括 __get__、__set__、__delete__ 三种魔法方法,只有当定义它们的一个类(descriptor类)的实例对象被赋给另一个类(owner类)的类属性时使用;
前文所学习的 property() 函数,实际上就是一个包含了三种描述符方法的描述符类;
注意描述符的实例对象,需要赋给类属性,访问实例层次上的描述符只会返回描述符本身,无法自动调用 __get__ 和 __set__ 方法。
- #创建描述符类
- class TestDescriptor:
- def __init__(self, nameinfo):
- self.nameinfo = nameinfo
-
- def __get__(self, instance, owner):
- return self.nameinfo
-
- #创建将描述符类实例对象赋给实例属性的类
- class TestOwner:
- def __init__(self, nameinfo2):
- self.nameinfo2 = nameinfo2
- self.x = TestDescriptor(self.nameinfo2)
-
- #调用由描述符类赋值的实例属性,不能正确调用魔法方法
- testx = TestOwner('test')
- testx.x
- <__main__.TestDescriptor object at 0x00000238691615B0>
- testx.x.__dict__
- {'nameinfo': 'test'}
- testx.x.nameinfo
- 'test'
-
- #创建将描述符类实例对象赋给类属性的类
- class TestOwner2:
- nameinfo2 = 'test'
- x = TestDescriptor(nameinfo2)
-
- #调用由描述符类赋值的类属性,正确调用魔法方法
- testy = TestOwner2()
- testy.y
- 'test'
获取 owner 类或 owner 的实例(instance)属性,返回属性的值;
设置 owner类的一个实例对象(instance)的属性为新的 value,没有返回值;
删除 owner类的一个实例对象(instance)的属性,没有返回值;
描述符方法的各个参数说明:
如下示例,简单表现描述符类的使用,以及描述符方法各个参数实际调用对象:
- #创建 descriptor 类,展示各个参数
- class TestDescriptor:
- def __get__(self, instance, owner):
- print(f'__get__方法各参数值为,self:{self},instance:{instance},owner:{owner}')
-
- def __set__(self, instance, value):
- print(f'__set__方法各参数值为,self:{self},instance:{instance},value:{value}')
-
- def __delete__(self, instance):
- print(f'__delete__方法各参数值为,self:{self},instance:{instance}')
-
- #创建 Owner 类,Owner 类中创建 descriptor 类的实例作为 Owner 类的一个属性
- class TestOwner:
- ins_D = TestDescriptor()
-
- #创建 Owner 类的实例
- ins_O = TestOwner()
-
- #Owner 类和类的实例对象
- ins_O
- <__main__.TestOwner object at 0x0000024E5B4E4F40>
- TestOwner
- <class '__main__.TestOwner'>
-
- #对 Owner 类中属性,也即 descriptor 类的实例作设置,调用 descriptor 类的 __set__ 方法
- class TestOwner:
- ins_O.ins_D = 'Testinfo: value'
- __set__方法各参数值为,self:<__main__.TestDescriptor object at 0x0000024E5B4A2670>,instance:<__main__.TestOwner object at 0x0000024E5B4E4F40>,value:Testinfo: value
-
- #对 Owner 类中属性,也即 descriptor 类的实例作读取,调用 descriptor 类的 __get__ 方法
- ins_O.ins_D
- __get__方法各参数值为,self:<__main__.TestDescriptor object at 0x0000024E5B4A2670>,instance:<__main__.TestOwner object at 0x0000024E5B4E4F40>,owner:<class '__main__.TestOwner'>
-
- #对 Owner 类中属性,也即 descriptor 类的实例作删除,调用 descriptor 类的 __delete__ 方法
- del ins_O.ins_D
- __delete__方法各参数值为,self:<__main__.TestDescriptor object at 0x0000024E5B4A2670>,instance:<__main__.TestOwner object at 0x0000024E5B4E4F40>
property 函数自行实现实操:
- #通过描述符类实现的类似 property 函数的 TestProperty 类
- class TestProperty:
- def __init__(self, getdef, setdef, deldef):
- self.getdef = getdef
- self.setdef = setdef
- self.deldef = deldef
-
- def __get__(self, instance, owner):
- return self.getdef(instance)
-
- def __set__(self, instance, value):
- self.setdef(instance,value)
-
- def __delete__(self, instance):
- self.deldef(instance)
-
- #调用描述符类:TestProperty,实现类似 property 函数效果
- class TestOwner:
- def __init__(self, info = 'testinfo'):
- self.info = info
-
- def getinfo(self):
- return self.info
-
- def setinfo(self, newinfo):
- self.info = newinfo
-
- def delinfo(self):
- del self.info
-
- ins_D = TestProperty(getinfo, setinfo, delinfo)
-
- #创建 TestOwner 的实例对象
- ins_O = TestOwner()
-
- #调用实例对象 ins_O 属性 ins_D,也即 TestProperty 的实例对象
- #获取 ins_O.ins_D 属性
- ins_O.ins_D
- 'testinfo'
- #设置 ins_O.ins_D 属性,并查询
- ins_O.ins_D = 'Hello, World!'
- ins_O.ins_D
- 'Hello, World!'
- #删除 ins_O.ins_D 属性,并验证删除成功
- del ins_O.ins_D
- ins_O.ins_D
- Traceback (most recent call last):
- File "<input>", line 1, in <module>
- File "<input>", line 8, in __get__
- File "<input>", line 21, in getinfo
- AttributeError: 'TestOwner' object has no attribute 'info'
温度类实操,要求如下:
- #创建摄氏度描述符类
- class Celsius:
- def __init__(self, value=0.0):
- self.value = float(f'{value:.2f}')
-
- def __get__(self, instance, owner):
- return self.value
-
- def __set__(self, instance, value):
- self.value = float(f'{value:.2f}')
-
- #创建华氏度描述符类
- class Fahrenheit:
- def __get__(self, instance, owner):
- return (instance.cel * 1.8) + 32
-
- def __set__(self, instance, value):
- tempcel = (float(value) - 32) / 1.8
- instance.cel = float(f'{tempcel:.2f}')
-
- #创建温度类
- class Temperature:
- cel = Celsius()
- fah = Fahrenheit()
-
- #创建温度类的实例
- tempx = Temperature()
-
- #通过温度类的实例,对类属性 cel/fah 做读取、设置,调用魔法方法成功
- tempx.cel
- 0.0
- tempx.cel = 25
- tempx.cel
- 25.0
- tempx.fah
- 77.0
- tempx.fah = 100
- tempx.cel
- 37.78