我希望执行以下操作:
class A(object):
def first_method(self):
print "I'm the first method!"
@some_decorator(A.first_method)
def second_method(self):
print "I'm the second method!"
但我遇到了解析装饰器时A
内部未定义的问题。我有什么方法可以在装饰器中引用A
吗?或者,如果我只是通过装饰器,绑定方法first_method
是否可以恢复first_method
属于A
?
答案 0 :(得分:1)
在python 3中,你可以说@some_decorator(first_method)
,它会起作用,因为所有方法都是类中的普通函数作为容器。
在python 2中,有一个复杂的绑定系统和unbound,instance-,class-和static方法。因此,您无法在类定义内部访问first_method
(如果完全形成,则直到该类)。
一个小的解决方法是将该类拆分为两个类:
class BaseA(object):
def first_method(self):
print "I'm the first method!"
class A(BaseA):
@some_decorator(BaseA.first_method)
def second_method(self):
print "I'm the second method!"
不是所有案例的最佳解决方案,但可行。
另外,请记住,在两种情况下(py2& py3),装饰器将引用此处声明的first_method
。如果任何后代类重新定义该方法,则新方法将不会在装饰器中使用;只会使用父母。
可能你根本不应该提到first_method
。相反,只需在装饰器的包装器中接受self
/ cls
第一个位置参数,然后在那里使用self.first_method
/ cls.first_method
:
import functools
def some_decorator(fn):
@functools.wraps(fn)
def wrapper(self, *args, **kwargs):
first_method = self.first_method
first_method()
return fn(self, *args, **kwargs)
return wrapper
class A(object):
def first_method(self):
print "I'm the first method of A!"
@some_decorator
def second_method(self):
print "I'm the second method!"
class B(A):
def first_method(self):
print "I'm the first method of B!"
A().second_method()
# I'm the first method of A!
# I'm the second method!
B().second_method()
# I'm the first method of B!
# I'm the second method!
如果您想使该方法可配置:
def some_decorator(method_name):
def decorator(fn):
@functools.wraps(fn)
def wrapper(self, *args, **kwargs):
first_method = getattr(self, method_name)
first_method()
return fn(self, *args, **kwargs)
return wrapper
return decorator
class A(object):
def first_method(self):
print "I'm the first method of A!"
@some_decorator('first_method')
def second_method(self):
print "I'm the second method!"
class B(A):
def first_method(self):
print "I'm the first method of B!"
答案 1 :(得分:0)
您可以将装饰器用作经典功能(不带@):
def some_decorator(arg):
# ...
pass
class A(object):
def first_method(self):
print("I'm the first method!")
def second_method(self):
print("I'm the second method!")
A.second_method = some_decorator(A.first_method)(A.second_method)