Python 实例方法的装饰器

Python 实例方法的装饰器,python,python-3.x,python-decorators,Python,Python 3.x,Python Decorators,将类的方法包装在“样板”Python装饰器中会将该方法视为常规函数,并使其丢失引用类实例对象的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu属性。这能避免吗 参加以下课程: class MyClass(object): def __init__(self, a=1, b=2): self.a = a self.b = b def meth(self): pass 如果meth()未装饰,MyClass().me

将类的方法包装在“样板”Python装饰器中会将该方法视为常规函数,并使其丢失引用类实例对象的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
属性。这能避免吗

参加以下课程:

class MyClass(object):
    def __init__(self, a=1, b=2):
        self.a = a
        self.b = b
    def meth(self):
        pass
如果
meth()
未装饰,
MyClass().meth.\uuuu self\uuuu
引用一个实例方法并启用类似于
setattr(my\u class\u object.meth.\uuu self\uu,'a',5)

但是当在装饰器中包装任何东西时,只传递函数对象;它实际绑定到的对象不会随它一起传递。(见答案。)

导入工具
定义(方法):
@functools.wrapps(方法)
def包装(*args,**kwargs):
#对方法做点什么。比如setattr
打印(hasattr(方法“自我”)
结果=方法(*args,**kwargs)
返回结果
返回包装器
类MyClass(对象):
定义初始化(self,a=1,b=2):
self.a=a
self.b=b
@装饰
def冰毒(自身):
通过
MyClass().meth()方法

#False如果修饰类的方法,则第一个参数始终是
self
对象(您可以使用
args[0]
访问它):

印刷品:

True
编辑:

您还可以在
wrapper
函数中指定
self
(基于注释):

印刷品还包括:

True

你在这里的主要误解是操作顺序

当调用
decoration()
decorator时,
meth()
还不是一个方法-它仍然是一个函数-只有当
class
块结束时,
meth
才被元类描述符转换成一个方法这就是为什么它还没有
\uuuuuuuuuuuuuuuuuuuuuu
(至今)

换句话说,要修饰方法,您必须忽略它们是方法的事实,并将它们视为正常函数,因为调用修饰器时它们就是这样的


事实上,原来的
meth
函数永远不会变成一个方法-相反,您从decorator返回的
wrapper
函数将是类的一部分,并且将是稍后获得
\uuuu self\uuuu
属性的函数。

让我澄清一下装饰过程:

当你在班级
MyClass
中用
decoration
装饰
meth
时,你正在做:

class MyClass(object):
    ... omit
    meth = decorate(meth)  # the meth in "()" is the original function.
如您所见,
decoration
方法
作为参数,并返回
包装器
,这是另一个函数。现在
MyClass
中原来的
meth
被新的
wrapper
所取代。因此,当您调用
myclass\u instance.meth()
时,您正在调用新的
包装器
函数


没有任何黑魔法,所以
self
可以被明确地传递到
wrapper
,使用
wrapper(self,*args,**kwargs)
接受
self
对我来说这看起来像是个XY问题。为什么要访问
\uuuu self\uuu
属性?为什么不添加
self
作为
wrapper
的第一个参数?为什么不能执行
setattr(args[0],'a',5)
args[0]
方法是
self
@aranfey我怀疑有人会说。。。例如:使用装饰器更新一个类属性,该类属性是方法调用及其参数的日志。@AndrejKesely啊,没错。我认为这应该行得通,真的有意义吗?使用
args[0]
而不是
def包装器(self,*args,**kwargs):
?有什么区别?
import functools

def decorate(method):
    @functools.wraps(method)
    def wrapper(self, *args, **kwargs):
        print(hasattr(self, 'a'))
        result = method(self, *args, **kwargs)
        return result
    return wrapper

class MyClass(object):
    def __init__(self, a=1, b=2):
        self.a = a
        self.b = b
    @decorate
    def meth(self):
        pass

MyClass().meth()
True
class MyClass(object):
    ... omit
    meth = decorate(meth)  # the meth in "()" is the original function.