python普通装饰器为什么能够给方法装饰,定义成类的话必须要定义__get__
最近在看PythonCookBook书,非常优秀的一本书,唯一的缺陷是书中的Python版本有点低,还有就是没有协程的相关信息。
在把装饰器定义成类那一章节:
import types from functools import wraps class Profiled: def __init__(self, func): wraps(func)(self) self.ncalls = 0 def __call__(self, *args, **kwargs): self.ncalls += 1 return self.__wrapped__(*args, **kwargs) def __get__(self, instance, owner): # print(instance, owner) if instance is None: return self else: return types.MethodType(self, instance)
书中写了一个用类写的装饰器,其中定义了__get__让我对函数中的__get__实现的逻辑有了更加清晰的认识。
class Spam: @Profiled def bar(self, x ): print(self, x)
当这个方法bar被Profiled类装饰后,返回的是Profiled的实例,单如果在Profiled内部没有定义__get__,一个对象是无法变成spam实例的绑定方法,虽然Profiled实例是一个可调用的对象。
例子中定义了__get__后,当调用这个bar方法,其实就是调用Profiled实例,bar = Profiled(bar),由于bar有__get__方法,首相调用该方法,通过MethodType将Profiled实例的__call__方法传递给instance,也就是spam实例。
这样的话,在运行被装饰的方法的时候,可以同样不需要填写self参数。
from functools import wraps def decorator1(func): @wraps(func) def wrapper(*args): print('Decorator1') return func(*args) return wrapper class Demo: # run = decorator1(run) @decorator1 def run(self, a): print(f'{a} is run') d = Demo() d.run('sidian') print(d.run)
上面是一个简单的装饰器函数,明显在一个方法被装饰的以后返回的还是一个方法(也可以说一个函数(对于类来说)返回的还是一个函数)
但函数中的__get__方法的作用,使的返回的函数能够重新变成实例的方法。
def __get__(self, instance, owner): # print(instance, owner) if instance is None: return self else: return types.MethodType(self, instance)
具体的执行逻辑可能还是跟上面的一样。找不到函数对象里面具体的魔法方法原码,网上是C写的,不懂C
其实这个主要还是面向对象过程的了解,还有就是Python对于函数的介绍的知识好少,函数这个对象内部的结构与逻辑的知识好少。