我正在尝试在我的类中创建一个计算特定函数的完整运行的方法。我想使用一个简单的装饰器。我发现了这个reference并重写了这个简单的脚本:
class myclass:
def __init__(self):
self.cnt = 0
def counter(function):
"""
this method counts the number of runtime of a function
"""
def wrapper(self, **args):
function(**args)
self.counter += 1
return wrapper
@myclass.counter
def somefunc():
print("hello from somefunc")
if __name__ == "__main__":
obj = myclass()
# or if comment @myclass.counter
# somefunc = myclass.counter(somefunc)
somefunc()
我当然得到:
TypeError: wrapper() missing 1 required positional argument: 'self'
我尝试将计数器重写为类方法:
class myclass:
def __init__(self):
self.cnt = 0
def counter(self, function):
"""
this function counts the number of runtime of a function
"""
def wrapper(**args):
function(**args)
self.cnt += 1
return wrapper
def somefunc():
print("hello from somefunc")
if __name__ == "__main__":
obj = myclass()
somefunc = obj.counter(somefunc)
for i in range(10):
somefunc()
print(obj.cnt)
哪个工作正常,但我认为它不是一个有效的装饰器定义。有没有办法在类方法中定义装饰器并将自身参数传递给它的函数?或者在类中定义装饰器是没用的?
编辑:------ 首先,我不能在类方法之外定义装饰。其次,我正在尝试创建一个运行特定函数(作为输入)的预定类,用于固定的时间间隔和特定的时间,因此我需要对其进行计数。
答案 0 :(得分:2)
所以我能够为你起草一些东西,下面是代码:
def count(func):
def wrapper(self):
TestClass.call_count += 1
func(self)
return wrapper
class TestClass(object):
call_count = 0
@count
def hello(self):
return 'hello'
if __name__ == '__main__':
x = TestClass()
for i in range(10):
x.hello()
print(TestClass.call_count)
为什么在类中设置装饰器会导致问题:
在课堂上有一个decorator function
并不是直截了当的。原因如下:
原因1
每个类方法都必须使用参数self
,它是调用函数的类的instance
。现在,如果您使装饰器函数采用self
参数,装饰器调用@count
将失败,因为它转换为count()
,但不传递self
参数,因此错误:
TypeError:wrapper()缺少1个必需的位置参数:'self'
原因2
现在,为了避免这种情况,您可以通过更改以下声明来使decorator
成为静态:
@staticmethod
def count(func):
pass
但是你又有另一个错误:
TypeError:'staticmethod'对象不可调用
这意味着你也不能拥有静态方法。如果在类中没有静态方法,则必须将self
实例传递给方法,但如果将self
实例传递给它,则@count
装饰器调用将不会不通过self
实例,因此无效。
所以here是一个很好地解释它的博客,与之相关的问题以及有哪些替代方案。
我个人更喜欢选择让helper class
来保存我可以使用的所有decorators
,而不是它所定义的唯一类。这将使您可以灵活地重用装饰器,而不是重新定义它们,这将遵循意识形态
代码一次,重复使用。
答案 1 :(得分:1)
您的第二个代码示例在功能上等同于标准装饰器。标准装饰器语法只是同一个东西的简写,即重新分配一个等于闭包的函数值(一个带有预定义参数的函数指针),其中闭包是装饰器包装器,将原件保存为预定义参数。
这是标准语法的等价物。请注意,您需要提前创建计数器类实例。装饰器语法引用该实例,因为它必须指示保存计数器的特定对象,而不仅仅是对象的类:
class myclass:
def __init__(self):
self.cnt = 0
def counter(self,function):
"""
this method counts the number of runtime of a function
"""
def wrapper(**args):
function(self,**args)
self.cnt += 1
return wrapper
global counter_object
counter_object = myclass()
@counter_object.counter
def somefunc(self):
print("hello from somefunc")
if __name__ == "__main__":
for i in range(10):
somefunc()
print(counter_object.cnt)