首页 新闻 会员 周边

类装饰器遇到的问题

0
[已关闭问题] 关闭于 2026-06-22 14:46

为啥没有加__get__就不是描述符吗,就直接调用__call__吗,c.method是查找的意思吧,你前面不是说了吗,c.method找method没有去cls.method找到了,并且cls.method是Decorator实例,所以找到的Decorator实例,然后再调用(3,4)相当于Decortor(method)(3,4),怎么加了__get__就是描述符了,c.method就是调用了?不对吧

class decorator:
    def __init__(self,func):
        wraps(func)(self)
        self.func = func
    def __call__(self, *args, **kwargs):
        return self.func(*args, **kwargs)
    def __get__(self, instance, owner):
        # 如果不是通过对象来调用的
        if instance is None:
            return self
        else:
            return types.MethodType(self, instance)

class cls:
    @decorator
    def method(self, x, y):
        return x + y

c = cls()
print(c.method(3, 4)) 
*Tesla*的主页 *Tesla* | 小虾三级 | 园豆:1834
提问于:2026-06-22 14:44
< >
分享
所有回答(1)
0

1. 你的理解完全正确的地方:属性查找

你说的:“c.method 是查找的意思,找到了 Decorator 实例,然后再调用 (3,4) 相当于 Decorator(method)(3,4)” —— 这前半部分完全正确!
Python 在遇到 c.method(3, 4) 时,确实分两步走:
  1. 第一步(查找):去 ccls 里面找 method 这个属性。找到了,发现它是一个 Decorator 实例对象。
  2. 第二步(调用):拿到这个对象后,加上 (3, 4),触发它的 __call__ 方法。
如果只有这两步,那确实会像你推导的那样,直接调用 __call__(3, 4),然后因为缺少 self 报错。

2. 为什么加了 __get__ 就变了?(Python 的隐藏规则)

Python 官方在设计属性查找机制时,加了一个极其重要的隐藏规则(也就是描述符协议):
当 Python 在类中查找属性时,如果发现找到的属性对象实现了 __get__ 方法,Python 就会“拦截”这个属性,不再直接返回它本身,而是去调用它的 __get__ 方法,把 __get__ 的返回值当作最终的属性。
这就是为什么它叫“描述符”(Descriptor):

我们代入代码来看看拦截过程

场景 A:没有 __get__ 

c.method  # Python 找到了 Decorator 实例,发现它没有 __get__
          # Python 决定:不管了,直接把 Decorator 实例原封不动地交出去!
          # 接着执行 (3, 4) -> 触发 __call__(3, 4) -> 报错!

场景 B:有 __get__ 的情况

 
c.method  # Python 找到了 Decorator 实例,发现它有 __get__!
          # Python 决定:我要拦截!我要调用它的 __get__!
          # 于是执行:result = Decorator实例.__get__(c, cls)
          # 你的代码里写了:return types.MethodType(self, c)
          # Python 拿到这个返回值(一个绑定方法),把它当作 c.method 的最终结果!
          
          # 接着执行 (3, 4) -> 触发这个绑定方法的调用 -> 自动传入 c 和 3, 4 -> 成功!

 

*Tesla* | 园豆:1834 (小虾三级) | 2026-06-22 14:46

这就是为什么它叫“描述符”(Descriptor)

 

在计算机科学中,Descriptor 的核心含义是“描述”(Description)或“说明”,它指的是用来描述某个对象(如文件、内存、硬件等)属性、状态或位置的数据结构

以我们常说的“文件描述符(File Descriptor)”为例,它本质上是一个整数(比如 0, 1, 2),在操作系统内核里,它指向一个数据结构。这个数据结构里包含了:
● 这个文件在磁盘上的真实物理路径在哪里?
● 当前读写指针到了文件的哪个位置?
● 这个文件是被只读打开,还是读写打开?
● 文件的权限是什么?

Descriptor 本身并不是你要操作的数据,而是关于数据的说明。因为它“描述”了打开文件的这些关键属性和状态,所以被称为“文件描述符”。

总结一下:
Descriptor 不是“符号”,而是“说明书”。计算机为了高效管理海量的底层资源,把复杂的资源属性打包成一个轻量级的“描述”,然后把这个“描述”交给你去使用。这就是“描述符”这个名字的真正由来!

支持(0) 反对(0) *Tesla* | 园豆:1834 (小虾三级) | 2026-06-23 13:04

没有  get ” 恰恰从反面证明了描述符的存在意义——如果没有这个“描述符协议”,Python 就不知道该如何拦截并接管这次属性访问,它只能把那个对象当成一个普通的死数据返回给你。 你提到的  get  就是触发这个拦截机制的钥匙!

支持(0) 反对(0) *Tesla* | 园豆:1834 (小虾三级) | 2026-06-23 13:08
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册