Python 实例方法的装饰器
将类的方法包装在“样板”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
\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.