鱼C论坛

 找回密码
 立即注册
查看: 1393|回复: 7

[知识点备忘] 第074讲:类和对象(XVII)

[复制链接]
发表于 2022-9-16 16:02:23 | 显示全部楼层 |阅读模式
购买主题 已有 2 人购买  本主题需向作者支付 5 鱼币 才能浏览
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-10-10 09:59:05 | 显示全部楼层
这节课讲的是一个有趣的技术——描述符,是我们前两节课所学的property()函数、类方法和静态方法背后的实现原理。描述符是指定义了__get__()、__set__()、__delete__()中任意一个或多个的类,这三个魔法方法分别用于拦截对象属性的读取、写入和删除操作,但管的是“别人家的属性”,使用时只需在另一个类中将描述符的实例化对象赋值给想要管理的属性即可。__get__()方法有三个参数:self、instance和owner。其中self对应描述符类的实例对象(被描述符拦截的属性),instance对应被描述符拦截的属性所在类的实例对象,owner对应被描述符拦截的属性所在类。借助描述符,我们不仅可以复刻之前学过的property()函数,还可以实现自己的property()函数,及其相应的getter()、setter()、deleter()方法。由此可见,描述符不愧为“木本水源”,一通百通啊!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2023-1-9 17:26:13 | 显示全部楼层
本帖最后由 Ensoleile 于 2023-1-10 00:27 编辑

描述符及property()实现原理
#描述符(property的原理):P177  实现了__get__()/__set__()/__delete__()三个中任何一个或多个方法的类,称为描述符
class D:
    def __get__(self, instance, owner):
        print(f'get~\nself -> {self}\ninstance -> {instance}\nowner -> {owner}')
    def __set__(self, instance, value):
        print(f'set~\nself -> {self}\ninstance -> {instance}\nvalue -> {value}')
    def __delete__(self, instance):# 不要混淆__del__()
        print(f'delete~\nself -> {self}\ninstance -> {instance}')

# 类D 为描述符,在另一个类里将他的实例化对象赋值给想要管理的属性就能启用他
class C:
    x = D()

c = C()
c.x = 250
# set~
# self -> <__main__.D object at 0x0000028D56A88FA0>
# instance -> <__main__.C object at 0x0000028D56A88F70>
# value -> 250
c.x
# get~
# self -> <__main__.D object at 0x0000026F6A728FA0>
# instance -> <__main__.C object at 0x0000026F6A728F70>
# owner -> <class '__main__.C'>
del c.x
# delete~
# self -> <__main__.D object at 0x0000026F6A728FA0>
# instance -> <__main__.C object at 0x0000026F6A728F70>

# self参数对应的是描述符这个类的实例对象<__main__.D object at 0x0000026F6A728FA0>
# instance对应的是被描述符拦截的属性所在的类的实例对象<__main__.C object at 0x0000026F6A728F70>
# owner参数对应被描述符拦截的属性所在的类<class '__main__.C'>

# 将案例修改为描述符的实现方式
######################案例##########################
# class C:
#     def __init__(self):
#         self._x = 250
#     def getx(self):
#         return self._x
#     def setx(self, value):
#         self._x = value
#     def delx(self):
#         del self._x
#     x = property(getx, setx, delx)
#
# c = C()
# print(c.x)#250
# c.x = 520
# print(c.x)#520
# del c.x
# print(c.__dict__)#{}
#########################################################
class D:
    def __get__(self, instance, owner):
        return instance._x
    def __set__(self, instance, value):
        instance._x = value
    def __delete__(self, instance):
        del instance._x

class C:
    def __init__(self, x=250):
        self._x = x
    x = D()

c = C()
print(c.x)#250
c.x = 520
print(c.x)#520
del c.x
print(c.__dict__)#{}
# 代码虽然能实现但不是一段健康的代码,类D中使用了类C中的属性_x

# property()的原理
class PropertyL:
    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 = 250
    def getx(self):
        return self._x
    def setx(self, value):
        self._x = value
    def delx(self):
        del self._x
    p = PropertyL(getx, setx, delx)

c = C()
print(c.p)#250
c.p = 520
print(c.p)#520
del c.p
print(c.__dict__)#{}

#实现getter()、setter()、deleter()方法
class PropertyL:
    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)
    def getter(self, func):
        self.fget = func
        return self
    def setter(self, func):
        self.fset = func
        return self
    def deleter(self, func):
        self.fdel = func
        return self

class D:
    def __init__(self):
        self._x = 250
    @PropertyL
    def x(self):
        return self._x
    @x.setter
    def x(self, value):
        self._x = value
    @x.deleter
    def x(self):
        del self._x

d = D()
print(d.x)# 250
d.x = 520
print(d.__dict__)# {'_x': 520}
del d.x
print(d.__dict__)# {}
#另一种写法
class E:
    def __init__(self):
        self._x = 250
    x = PropertyL()
    @x.getter
    def x(self):
        return self._x
    @x.setter
    def x(self, value):
        self._x = value
    @x.deleter
    def x(self):
        del self._x

e = E()
print(e.x)# 250
e.x = 520
print(e.__dict__)# {'_x': 520}
del e.x
print(e.__dict__)# {}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2023-2-26 15:36:11 | 显示全部楼层
本帖最后由 我又可以了 于 2023-2-28 14:44 编辑
class D:
        def __get__(self,instance,owner):
                return instance._x
        def __set__(self,instance,value):
                instance._x=value
        def __delete__(self,instance):
                del instance._x

                
>>> class C:
        def __init__(self):
                self._x=250
        x=D()

        
>>> c=C()
>>> c.x
250
>>> c.x=520
>>> c.__dict__
{'_x': 520}
>>> del c.x
>>> c.__dict__
{}
WM
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-4-15 09:30:55 | 显示全部楼层
Ensoleile 发表于 2023-1-9 17:26
描述符及property()实现原理

大佬,我想给78-80加一个注解:
print(self.fget)#C.getx
print(self.fset)#C.setx
print(self.fdel)#C.delx
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-10 09:00:13 | 显示全部楼层
太强了,yyds,老哥。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-12 16:47:05 | 显示全部楼层
这节看不懂,,
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 6 天前 | 显示全部楼层
今天课程又补充完善了!
编程其实挺难的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-10-23 04:39

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表