Python中魔法方法:描述符的个人理解
对小甲鱼的046魔法方法: 描述符课程中的例子的解析(个人笔记)
先看例子
class Descriptor_Centigrade: #定义描述符类1,摄氏度描述符
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 Descriptor_Fahrenheit: #定义描述符类2,华氏度描述符
def __get__(self, instance, owner):
return instance.c * 1.8 + 32
def __set__(self, instance, value):
instance.c = (float(value) - 32) / 1.8
class Temperature: #定义温度类
c = Descriptor_Centigrade()
f = Descriptor_Fahrenheit()
该段代码定义了两种描述符,又定义了一个温度类,实现了摄氏度华氏度的自动转换并打印转换结果这样一个简单的功能。
效果如下:
In [2]: t = Temperature() #实例化温度类的对象
In [3]: t.c
Out[3]: 26.0
In [4]: t.f
Out[4]: 78.80000000000001
In [5]: t.c = 50
In [6]: t.f
Out[6]: 122.0
In [7]: t.f = 100
In [8]: t.c
Out[8]: 37.77777777777778
首先,以魔法方法__get__为例,解释一下其内部参数:
__get__(self, instance, owner)
,查看行为发生时自动执行。其中:
self
也就是该描述符类的实例对象自己,上例中为c
;
instance
表示类(上例温度类,非描述符类)的实例对象,例如t = Temperature
,那么这个t
就是instance
;
owner
就表示Temperature
这个类。
而魔法方法__set__:
__set__(self, instance, value)
也是一样,不同的value
代表赋值行为发生时,如上例t.c = 50
,等号右端的值50
。
弄懂了这两个魔法方法,下面开始解析流程:
首先,t = Temperature
创建一个温度类的实例化对象;
然后,执行t.c
,会创建描述符类1(摄氏度描述符类)的实例对象(即c = Descriptor_Centigrade()
),并自动赋初值
value = 26.0
,又由这个t.c
查看行为自动触发__get__
方法,可看作__get__(c, t, Temperature)
,返回self.value
,即Out[3]: 26.0
;
接着,执行t.f
,同样在创建描述符类2(华氏度描述符类)的实例对象(即f = Descriptor_Fahrenheit()
)同时触发
__get__
方法,
返回instance.c * 1.8 + 32
也就是t.c * 1.8 + 32
,即Out[4]: 78.80000000000001
;
继续,当赋值行为发生时,自动调用__set__
方法;
输入In [5]: t.c = 50
,自动调用描述符类1的__set__
方法,执行self.value = float(value)
将50.0
重新赋给t.c
;
输入In [6]: t.f
,自动调用描述符类2的__set__
方法,执行return instance.c * 1.8 + 32
返回新的计算值,即
Out[6]: 122.0
;
相反,当先赋值给t.f
时:
In [7]: t.f = 100
,会自动调用描述符类2的__set__
方法,执行instance.c = (float(value) - 32) / 1.8
,将t.c
改写成新值37.77777777777778
,故此时调用In [8]: t.c
,会显示Out[8]: 37.77777777777778
。
至此结束。
对各个参数的简单解释也写在了代码片上,如下:
class Descriptor_Centigrade:
def __init__(self, value = 26.0):
self.value = float(value)
#魔法方法__get__(self, instance, owner)参数的解释:
# instance:类的实例对象(比如 t=Temperature, 那么这个 t 就是 instance)
# ↗
# self:描述符的实例对象 ( c ) ↗ owner:类,也就是 Temperature
# ↑ ↗ ↗
# ↑ ↗ ↗
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
self.value = float(value)
class Descriptor_Fahrenheit:
def __get__(self, instance, owner):
return instance.c * 1.8 + 32
def __set__(self, instance, value):
instance.c = (float(value) - 32) / 1.8
class Temperature:
c = Descriptor_Centigrade()
f = Descriptor_Fahrenheit()
#使用时,实例化时:
# t = Temperature() t:类的实例对象
# c = Descriptor_Centigrade() c:描述符1的实例对象
# f = Descriptor_Fahernhiet() f:描述符2的实例对象