class 方法中的装饰器:与 'getattr' 兼容
Decorators in class methods: compatibility with 'getattr'
我需要为 class 方法制作包装器,以便在调用特定方法后 and/or 之前执行。
这是一个最小的例子:
class MyClass:
def call(self, name):
print "Executing function:", name
getattr(self, name)()
def my_decorator(some_function):
def wrapper():
print("Before we call the function.")
some_function()
print("After we call the function.")
return wrapper
@my_decorator
def my_function(self):
print "My function is called here."
engine = MyClass()
engine.call('my_function')
这让我在 getattr(self, name)()
行出错:
TypeError: 'NoneType' object is not callable
如果我在 class 方法之前注释掉装饰器,它会完美地工作:
class MyClass:
def call(self, name):
print "Executing function:", name
getattr(self, name)()
def my_decorator(some_function):
def wrapper():
print("Before we call the function.")
some_function()
print("After we call the function.")
return wrapper
# @my_decorator
def my_function(self):
print "My function is called here."
engine = MyClass()
engine.call('my_function')
输出为:
Executing function: my_function
My function is called here.
装饰器本身与教科书示例相同。在使用 getattr
.
调用 Python 中的装饰方法时,似乎在低级别出现了问题
您对如何修复此代码有任何想法吗?
这与getattr()
无关。当您尝试直接调用 my_function()
时,您会得到完全相同的错误:
>>> engine.my_function()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
你有两个问题:
您的装饰器从不 return 编辑 wrapper
,因此 None
被 return 编辑。这个 return 值取代了 my_function
并且是您错误的直接原因; MyClass.my_function
设置为 None
:
>>> MyClass.my_function is None
True
您的包装器不带任何参数,包括 self
。一旦你正确地return它就需要它来工作。
第一个问题通过取消 return wrapper
行的缩进得到解决;它目前是 wrapper
函数 本身 的一部分,应该是 my_decorator
的一部分:
def my_decorator(some_function):
def wrapper(self):
print("Before we call the function.")
# some_function is no longer bound, so pass in `self` explicitly
some_function(self)
print("After we call the function.")
# return the replacement function
return wrapper
您的问题只得到了部分回答。以下是如何修改 wrapper
(以及 call()
)方法,以便它们接受额外的参数——这将使其完全工作(以及在 Python 2 和 3 中):
class MyClass:
def call(self, name, *args, **kwargs):
print("Executing function: {!r}".format(name))
getattr(self, name)(*args, **kwargs)
def my_decorator(some_function):
def wrapper(self, *args, **kwargs):
print("Before we call the function.")
retval = some_function(self, *args, **kwargs)
print("After we call the function.")
return retval
return wrapper
@my_decorator
def my_function(self):
print("My function is called here.")
del my_decorator # Not a permanent part of class.
engine = MyClass()
engine.call('my_function')
输出:
Executing function: 'my_function'
Before we call the function.
My function is called here.
After we call the function.
我需要为 class 方法制作包装器,以便在调用特定方法后 and/or 之前执行。
这是一个最小的例子:
class MyClass:
def call(self, name):
print "Executing function:", name
getattr(self, name)()
def my_decorator(some_function):
def wrapper():
print("Before we call the function.")
some_function()
print("After we call the function.")
return wrapper
@my_decorator
def my_function(self):
print "My function is called here."
engine = MyClass()
engine.call('my_function')
这让我在 getattr(self, name)()
行出错:
TypeError: 'NoneType' object is not callable
如果我在 class 方法之前注释掉装饰器,它会完美地工作:
class MyClass:
def call(self, name):
print "Executing function:", name
getattr(self, name)()
def my_decorator(some_function):
def wrapper():
print("Before we call the function.")
some_function()
print("After we call the function.")
return wrapper
# @my_decorator
def my_function(self):
print "My function is called here."
engine = MyClass()
engine.call('my_function')
输出为:
Executing function: my_function
My function is called here.
装饰器本身与教科书示例相同。在使用 getattr
.
您对如何修复此代码有任何想法吗?
这与getattr()
无关。当您尝试直接调用 my_function()
时,您会得到完全相同的错误:
>>> engine.my_function()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
你有两个问题:
您的装饰器从不 return 编辑
wrapper
,因此None
被 return 编辑。这个 return 值取代了my_function
并且是您错误的直接原因;MyClass.my_function
设置为None
:>>> MyClass.my_function is None True
您的包装器不带任何参数,包括
self
。一旦你正确地return它就需要它来工作。
第一个问题通过取消 return wrapper
行的缩进得到解决;它目前是 wrapper
函数 本身 的一部分,应该是 my_decorator
的一部分:
def my_decorator(some_function):
def wrapper(self):
print("Before we call the function.")
# some_function is no longer bound, so pass in `self` explicitly
some_function(self)
print("After we call the function.")
# return the replacement function
return wrapper
您的问题只得到了部分回答。以下是如何修改 wrapper
(以及 call()
)方法,以便它们接受额外的参数——这将使其完全工作(以及在 Python 2 和 3 中):
class MyClass:
def call(self, name, *args, **kwargs):
print("Executing function: {!r}".format(name))
getattr(self, name)(*args, **kwargs)
def my_decorator(some_function):
def wrapper(self, *args, **kwargs):
print("Before we call the function.")
retval = some_function(self, *args, **kwargs)
print("After we call the function.")
return retval
return wrapper
@my_decorator
def my_function(self):
print("My function is called here.")
del my_decorator # Not a permanent part of class.
engine = MyClass()
engine.call('my_function')
输出:
Executing function: 'my_function'
Before we call the function.
My function is called here.
After we call the function.