鱼C论坛

 找回密码
 立即注册
查看: 2087|回复: 8

[已解决]cls是None吗

[复制链接]
发表于 2023-6-9 20:27:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 VPython999 于 2023-6-10 10:12 编辑

如图,这是小甲鱼《零基础入门学习Python》最新版P77上讲的,我想问下,最后d.__doc__执行的结果为什么没有打印"旺财"呢?self是__doc__,obj是d,cls应该没有传入吧,所以应该满足"cls is None"这个条件吧?是我理解有问题吗?请大神指教!
class MethodType:
    def __init__(self,func,obj):
        self.__func__=func
        self.__self__=obj
    def __call__(self,*args,**kwargs):
        func=self.__func__
        obj=self.__self__
        print("小白")
        return func(obj,*args,**kwargs)

    
class ClassMethod:
    def __init__(self,f):
        self.f=f
    def __get__(self,obj,cls=None):
        if cls is None:
            print("旺财")
            cls=type(obj)
        if hasattr(type(self.f),'__get__'):
            print(f"来福,type(self.f)->{type(self.f)}")
            return self.f.__get__(cls,cls)
        return MethodType(self.f,cls)

    
class D:
    @ClassMethod
    @property
    def __doc__(cls):
        return f"I love FishC.--from class {cls.__name__}"

d=D()
d.__doc__
来福,type(self.f)-><class 'property'>
'I love FishC.--from class D'
最佳答案
2023-6-12 05:55:14
本帖最后由 阿奇_o 于 2023-6-12 06:13 编辑
VPython999 发表于 2023-6-11 11:27
非常非常感谢您的回复,还想请教一下,您说“cls除了参数初始化时为None,其后都不会是None”,这个能举 ...


1. 因为None本身是个特殊的类型,其内部不包含任何数据。基本作用就是“先占个坑”。。
初始化时常用,就是告诉编译器,我这有个箱子,具体是属于什么类型、放什么东西/数据,等后面用到了在决定。
这个就不用举例子了吧,我问你吃饭了没,没有就是没有,None is None。。有就是有,吃了就是吃了,具体吃什么就看你自己了。。

2. 简单点说,就是利用装饰器的机制,把函数再套一两层逻辑,其本质就是嵌套函数(基本就两种:函数装饰器套函数,类装饰器套函数)。
另外一个关键就是:要把 函数当做一个对象(“一等对象”), func() 后面加括号才会执行其内部逻辑。
@property是“类装饰器”+“描述符/修饰器”的典型用法。   
注意,property是Python内置的一个类,因为类class X天然可以be called 被调用(因为__call__),所以它天然能作为 装饰器也不奇怪。
@property 会把 点访问__doc__对象(任何X.__doc__ 这一写法/访问操作),都会根据“描述符协议”的__get__逻辑来走。
具体逻辑看官方手册Howtos指南的等价形式、或深究其源码细节。

这个property类,最大的好处就是简化代码,和返回一些需要动态查找或中间处理的属性数据。

总之,基本上,你只需要知道 @property 可以让一个方法,能像普通属性那样被访问,然后被执行,即可。(
(你甚至可以把 类的方法和普通属性,统一看做 属性Attributes。 你想想,一切不都是“对象”么?
研究对象,不就是给它起个“名”name,看看它有哪些“属性特征”,再如何“增删改查”这些属性特征数据。。)

Anyway,反正就是:对象那点事,以及逻辑与套娃的艺术。。



想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-6-10 10:44:06 | 显示全部楼层
请问何时能审核通过啊?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-11 04:39:43 | 显示全部楼层
本帖最后由 阿奇_o 于 2023-6-11 04:47 编辑

在__get__中(参数里),第三个参数其实 objtype,就是你绑定的 实例对象所属的类,所以cls除了参数初始化时为None,其后都不会是None,只能是 obj 的所属类。

ps: 这里要完全理解,估计不是一时半会的,因为它涉及了 魔法方法、描述符、装饰器,三个“难点”,其例子也有点“为了举例而举例”, 而且还混着来用。。

--------------------- 补充(能否理解就看你自己了) --------------------
一句话,两个关键点:

ClassMethod是 描述符(类) ,因为它实现了__get__  。然后呢?然后,就是:
一句话:"要使用描述符 必须 实例化描述符,并 赋值给 一个类变量(名)"
关键点:一个是实例化,一个是赋值(绑定)。

        - 在class D中,它借助 装饰器的功能,先是实例化了ClassMethod。(注意,@X类装饰器,在执行时,就是调用该类的默认的或你自定义的__call__方法。类装饰器时,就是其实例化,函数装饰器时,则是执行该函数。你的MethodType类中就是重写了__call__的例子)
        - 然后,又借助@property类装饰器,把__doc__绑定到class D上(cls就是D),即让 __doc__成为一个 类变量(类属性)。不然,没法使用描述符,描述符实例 必须绑定/赋值 到类变量上。

        所以这里 近似等价于:
        class D:
                __doc__ = ClassMethod()

        小细节:__doc__原本也默认会绑定到类上,这里准确来说,不是让其“成为”,而是“重写”__doc__的功能(其默认是回显DocString,也就是你写在三个引号里的文档注释)



想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-11 08:03:21 | 显示全部楼层
这段代码主要关注在Python的数据描述符(data descriptor)和方法描述符(method descriptor)概念上。当你使用  d.__doc__  时,Python的属性查找机制实际上会执行  D.__doc__.__get__(d, D) 。

这里  @ClassMethod  和  @property  是两个装饰器,执行顺序是由下到上,所以  @property  会先于  @ClassMethod  执行。 property  是 Python 的内置类型,它是一个数据描述符,数据描述符实现了  __get__  和  __set__  方法。而  ClassMethod  则实现了  __get__  方法,是一个方法描述符。

在Python的描述符协议中,对于一个类实例  d ,当你通过  d.__doc__  访问时,Python会先查找类的字典,看有没有实现了 __get__ 的描述符,如果有,则调用它的 __get__ 方法。如果在类字典中找不到,Python会查找实例字典。而数据描述符(如 property )优先于实例字典,而方法描述符则优先于类字典。

所以当你执行  d.__doc__ ,实际上会触发  D.__doc__.__get__(d, D) 。在这个调用过程中, D.__doc__  是  ClassMethod  的实例,并且它的  f  属性是  property  的实例。所以, D.__doc__.__get__(d, D)  其实就是调用  ClassMethod.__get__(self, obj, cls) ,其中, self  是  ClassMethod  的实例, obj  是  d , cls  是  D 。

在  ClassMethod.__get__  方法内部, if cls is None:  这个条件没有满足,因为传入的  cls  参数是  D  类,而不是  None 。然后它检查  self.f (也就是  property  的实例)是否有  __get__  方法,有的话就调用它。所以,“旺财”没有打印出来,而是打印出来了“来福,type(self.f)-><class 'property'>”,然后返回  I love FishC.--from class D 。

这就是为什么你看到这样的输出的原因。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-11 11:27:03 | 显示全部楼层
阿奇_o 发表于 2023-6-11 04:39
在__get__中(参数里),第三个参数其实 objtype,就是你绑定的 实例对象所属的类,所以cls除了参数初始化 ...

非常非常感谢您的回复,还想请教一下,您说“cls除了参数初始化时为None,其后都不会是None”,这个能举一个cls为None的例子吗?
还有就是,能麻烦您帮忙解答最后一个问题吗?为什么只要有@property,调用__doc__时就可以不加括号,这具体是怎么实现的呢?谢谢!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-11 11:29:54 | 显示全部楼层
isdkz 发表于 2023-6-11 08:03
这段代码主要关注在Python的数据描述符(data descriptor)和方法描述符(method descriptor)概念上。当你 ...

非常非常感谢您的回复,您跟楼上一样,都帮我大忙了,但是楼上回答的早,我就定楼上答案为最佳答案了哈
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-11 14:21:38 | 显示全部楼层
VPython999 发表于 2023-6-11 11:29
非常非常感谢您的回复,您跟楼上一样,都帮我大忙了,但是楼上回答的早,我就定楼上答案为最佳答案了哈{: ...

不客气
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-12 05:55:14 | 显示全部楼层    本楼为最佳答案   
本帖最后由 阿奇_o 于 2023-6-12 06:13 编辑
VPython999 发表于 2023-6-11 11:27
非常非常感谢您的回复,还想请教一下,您说“cls除了参数初始化时为None,其后都不会是None”,这个能举 ...


1. 因为None本身是个特殊的类型,其内部不包含任何数据。基本作用就是“先占个坑”。。
初始化时常用,就是告诉编译器,我这有个箱子,具体是属于什么类型、放什么东西/数据,等后面用到了在决定。
这个就不用举例子了吧,我问你吃饭了没,没有就是没有,None is None。。有就是有,吃了就是吃了,具体吃什么就看你自己了。。

2. 简单点说,就是利用装饰器的机制,把函数再套一两层逻辑,其本质就是嵌套函数(基本就两种:函数装饰器套函数,类装饰器套函数)。
另外一个关键就是:要把 函数当做一个对象(“一等对象”), func() 后面加括号才会执行其内部逻辑。
@property是“类装饰器”+“描述符/修饰器”的典型用法。   
注意,property是Python内置的一个类,因为类class X天然可以be called 被调用(因为__call__),所以它天然能作为 装饰器也不奇怪。
@property 会把 点访问__doc__对象(任何X.__doc__ 这一写法/访问操作),都会根据“描述符协议”的__get__逻辑来走。
具体逻辑看官方手册Howtos指南的等价形式、或深究其源码细节。

这个property类,最大的好处就是简化代码,和返回一些需要动态查找或中间处理的属性数据。

总之,基本上,你只需要知道 @property 可以让一个方法,能像普通属性那样被访问,然后被执行,即可。(
(你甚至可以把 类的方法和普通属性,统一看做 属性Attributes。 你想想,一切不都是“对象”么?
研究对象,不就是给它起个“名”name,看看它有哪些“属性特征”,再如何“增删改查”这些属性特征数据。。)

Anyway,反正就是:对象那点事,以及逻辑与套娃的艺术。。



想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2023-6-12 11:32:43 | 显示全部楼层
阿奇_o 发表于 2023-6-12 05:55
1. 因为None本身是个特殊的类型,其内部不包含任何数据。基本作用就是“先占个坑”。。
初始化时常用 ...

懂啦,感谢您耐心的解释
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-27 12:19

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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