鱼C论坛

 找回密码
 立即注册
查看: 237|回复: 2

为什么”来福“的位置不太对?

[复制链接]
发表于 2024-3-5 19:25:40 | 显示全部楼层 |阅读模式

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

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

x
class MethodType:
        def __init__(self, func, object):
                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__}"
跟着小甲鱼的视频里面敲的,为什么我在实例化的时候,就会打印”来福“那一段文字呢?视频里是访问__doc__的时候才会打印的才对呀~

本帖被以下淘专辑推荐:

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

使用道具 举报

发表于 2024-3-5 19:26:00 | 显示全部楼层
首先,让我们来解释一下代码中的几个关键点。

1. `@ClassMethod`装饰器:这是一个自定义的装饰器,用于修饰类方法。在本例中,它被用于修饰属性方法`__doc__`。

2. `ClassMethod`类:这个类是为了模拟类方法的特性而创建的。它实现了`__get__`方法,当我们通过实例去访问属性时会被调用。

3. `MethodType`类:这个类用于将函数与对象绑定在一起,并返回一个可调用的对象。

现在让我们来看看代码中`ClassMethod`的使用:

  1. class D:
  2.     @ClassMethod
  3.     @property
  4.     def __doc__(cls):
  5.         return f"I love FishC. -- from class {cls.__name__}"
复制代码


在这里,我们将`ClassMethod`装饰器应用到`__doc__`属性上。当我们通过实例去访问`__doc__`属性时,`__get__`方法会被调用,并且会打印出"来福, type(self.f)->{type(self.f)}"。

这是因为在`__get__`方法中,我们首先检查`cls`是否为None。在这种情况下,我们使用`type(obj)`来获取`obj`的类。而在我们实例化`D`类的时候,`obj`是None,所以会打印出"来福"这段文字。

如果你想避免打印"来福"这段文字,可以修改`__get__`方法中的代码如下:

  1. def __get__(self, obj, cls=None):
  2.     if cls is None and obj is not None:
  3.         cls = type(obj)
  4.     if hasattr(type(self.f),'__get__'):
  5.         return self.f.__get__(cls,cls)
  6.     return MethodType(self.f, cls)
复制代码


这样修改后,只有在访问`__doc__`属性时才会打印出"I love FishC. -- from class D",而不会打印"来福"。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 0 反对 1

使用道具 举报

发表于 2024-3-5 20:16:57 | 显示全部楼层
在你提供的代码中,出现了一个小错误,这可能是造成你观察到的行为与预期不符的原因。在 MethodType 类的 __init__ 方法中,你初始化了 self.__self__ = obj,但是参数名是 object,不是 obj。这应该更正为 self.__self__ = object。然而,这个错误并不直接影响到“来福”那段文字的打印问题。

原因在于,你的 ClassMethod 类装饰器在被应用到通过 @property 装饰的 __doc__ 属性时,已经触发了其 __get__ 方法的调用。具体来说,当Python解释器加载你的类定义时,它会处理 @ClassMethod 和 @property 装饰器。由于 @ClassMethod 装饰器被设计为在属性访问时介入,其 __get__ 方法会在尝试获取 __doc__ 属性的描述符时被调用。

这里的关键在于,@property 本身创建了一个描述符,@ClassMethod 装饰器进一步包装了这个描述符。当Python试图解析这个被双重装饰的 __doc__ 属性时,它会调用 ClassMethod 的 __get__ 方法来获取最终的可调用对象。这一过程发生在类的定义阶段,而不是在属性访问时,因为 @property 已经将 __doc__ 方法包装为一个属性访问的描述符,然后 @ClassMethod 再次包装这个描述符,这就导致了 __get__ 方法的立即调用。

这个过程中,当 __get__ 方法检查 self.f(实际上是通过 @property 装饰的 __doc__ 方法)时,由于它发现这个对象有自己的 __get__ 方法(@property 创建的描述符具有 __get__ 方法),它打印出了“来福”并返回了 self.f.__get__(cls,cls),这就是为什么你在实例化类 D 时就看到了那段文字。这种行为与预期不符,因为装饰器的组合使用方式导致了一些意外的早期调用行为。

要解决这个问题,你可能需要重新考虑你的装饰器设计,或者避免将 @ClassMethod 和 @property 一起使用在同一个方法上。如果你的目的是创建一个可以作为类方法访问的属性,可能需要一个更简单的实现策略。

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-4 21:09

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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