Bra*_*mon 6 python python-3.x python-decorators
将类的方法包装在“样板”Python 装饰器中会将该方法视为常规函数,并使其失去__self__引用类实例对象的属性。这可以避免吗?
参加以下课程:
class MyClass(object):
def __init__(self, a=1, b=2):
self.a = a
self.b = b
def meth(self):
pass
Run Code Online (Sandbox Code Playgroud)
如果meth()未修饰,MyClass().meth.__self__则引用实例方法并启用类似setattr(my_class_object.meth.__self__, 'a', 5).
但是当将任何东西包装在装饰器中时,只传递函数对象;它实际绑定的对象不会随之传递。(请参阅此答案。)
import functools
def decorate(method):
@functools.wraps(method)
def wrapper(*args, **kwargs):
# Do something to method.__self__ such as setattr
print(hasattr(method, '__self__'))
result = method(*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()
# False <--------
Run Code Online (Sandbox Code Playgroud)
这可以被覆盖吗?
您在这里的主要误解是操作顺序。
当decorate()装饰器被调用时,meth()它还不是一个方法 - 它仍然是一个函数 - 只有当class块结束时meth,元类描述符才会将其转换为方法!__self__- 这就是为什么它(还)没有。
换句话说,要装饰方法,您必须忽略它们是方法的事实,并将它们视为普通函数 - 因为这就是调用装饰器时它们的样子。
事实上,原始meth函数永远不会变成方法 - 相反,从装饰器返回的函数将成为类的一部分,并且将是稍后wrapper获取属性的函数。__self__
如果您装饰类的方法,第一个参数始终是self对象(您可以使用 访问它args[0]):
import functools
def decorate(method):
@functools.wraps(method)
def wrapper(*args, **kwargs):
print(hasattr(args[0], 'a'))
result = method(*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()
Run Code Online (Sandbox Code Playgroud)
印刷:
True
Run Code Online (Sandbox Code Playgroud)
编辑:
self您还可以在您的函数中指定wrapper(基于注释):
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()
Run Code Online (Sandbox Code Playgroud)
还打印:
True
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3309 次 |
| 最近记录: |