In Python, is it possible to decorate both a class and non-class method with the same decorator?
我有一个简单的异常日志修饰器,当脚本抛出异常时,它可以方便地向自己发送电子邮件。
1 2 3 4 5 6 7 8 | def logExceptions(func): def wrapper(): try: func() except Exception, e: logger.exception(e) return wrapper |
但是,如果我想要修饰一个类方法,我必须修改wrapper()以获得一个"self",否则我会得到以下错误:
1 | TypeError: wrapper() takes no arguments (1 given) |
当然,在这一点上,我不能用它来修饰任何非类方法,因为这样会发生以下错误:
1 | TypeError: wrapper() takes exactly 1 argument (0 given) |
有没有一个干净的方法来解决这个问题?谢谢=
通常情况下,定义包装器以便它接受
另外,我觉得你所说的"类方法"就是python所说的"实例方法",而你所说的"非类方法"就是python所说的"函数"。python中的"非类方法"(例如实例方法)采用
实例方法
首先要注意的是:静态方法和类方法都是函数,所以标准函数规则主要应用于它们。我理解您的问题是关于静态方法(没有传递额外参数)和类方法(在第一个参数中接收类)之间的区别:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Test(object): def standard_method(*args, **kwargs): # it is instance method (first argument will be instance) return args, kwargs @classmethod def class_method(*args, **kwargs): # it is class method (first argument will be class) return args, kwargs @staticmethod def static_method(*args, **kwargs): # it is static method (receives only arguments passed explicitly) return args, kwargs |
证据(或更确切地说是不言自明的例子)如下:
1 2 3 4 5 6 7 | >>> t = Test() >>> t.standard_method() ((<__main__.Test object at 0x0000000002B47CC0>,), {}) >>> t.class_method() ((<class '__main__.Test'>,), {}) >>> t.static_method() ((), {}) |
如您所见,根据您选择的方法类型,传递的参数列表有所不同。您面临的问题是变量个数的参数。
解决方案有一个解决方案-使用参数解包:
1 2 3 4 5 6 | def some_decorator(func): def wrapper(*args, **kwargs): # do something here # args is a tuple with positional args, kwargs is dict with keyword args return func(*args, **kwargs) return wrapper |
之后,
因此,这两个例子都是有效的:
1 2 3 4 5 6 7 | @some_decorator def say_hello(): print 'hello' @some_decorator def say_something(something): print something |
附录
为了给您提供完整的示例,最好使用这种结构(注意
1 2 3 4 5 6 7 8 | from functools import wraps def some_decorator(func): @wraps(func) def wrapper(*args, **kwargs): # do something here # args is a tuple with positional args, kwargs is dict with keyword args return func(*args, **kwargs) return wrapper |
原因在
装饰的另一种选择是使用