类和对象11:描述符方法

目录

1. 描述符基础

2. 描述符方法

2.1 方法简述

__get__(self, instance, owner):

__set__(self, instance, value):

__delete__(self, instance):

2.2 方法参数

2.3 简单示例

3. 操作实例


1. 描述符基础

描述符(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'

2. 描述符方法

2.1 方法简述

__get__(self, instance, owner):

获取 owner 类或 owner 的实例(instance)属性,返回属性的值;

__set__(self, instance, value):

设置 owner类的一个实例对象(instance)的属性为新的 value,没有返回值;

__delete__(self, instance):

删除 owner类的一个实例对象(instance)的属性,没有返回值;

2.2 方法参数

描述符方法的各个参数说明:

  • self:descriptor类,即描述符类的实例对象;
  • instance:owner类的实例对象
  • owner:owner类
  • value:用于设置属性的值

2.3 简单示例

如下示例,简单表现描述符类的使用,以及描述符方法各个参数实际调用对象:

#创建 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>

3. 操作实例

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

燃烧的火鸟啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值