Python动态为类的方法添加装饰器
假设我有一个类:
class x:
def first_x_method(self):
print 'doing first_x_method stuff...'
def second_x_method(self):
print 'doing second_x_method stuff...'
还有这个装饰器:
class logger:
@staticmethod
def log(func):
def wrapped(*args, **kwargs):
try:
print "Entering: [%s] with parameters %s" % (func.__name__, args)
try:
return func(*args, **kwargs)
except Exception, e:
print 'Exception in %s : %s' % (func.__name__, e)
finally:
print "Exiting: [%s]" % func.__name__
return wrapped
我该如何写另一个装饰器 otherdecorator
,使得:
@otherdecorator(logger.log)
class x:
def first_x_method(self):
print 'doing x_method stuff...'
def first_x_method(self):
print 'doing x_method stuff...'
跟这个一样:
class x:
@logger.log
def first_x_method(self):
print 'doing first_x_method stuff...'
@logger.log
def second_x_method(self):
print 'doing second_x_method stuff...'
或者实际上替换掉:
@otherdecorator(logger.log)
class x:
用这个:
@otherdecorator
class x:
其中 otherdecorator
包含所有的功能。(我对Python不太熟悉,所以请轻点)
2 个回答
2
这里有一个用类实现的 trace
装饰器版本,它可以满足另一个需求:将一个函数传入,用来装饰被装饰类的所有成员函数。
import inspect
def log(func):
def wrapped(*args, **kwargs):
try:
print "Entering: [%s] with parameters %s" % (func.__name__, args)
try:
return func(*args, **kwargs)
except Exception, e:
print 'Exception in %s : %s' % (func.__name__, e)
finally:
print "Exiting: [%s]" % func.__name__
return wrapped
class trace(object):
def __init__(self, f):
self.f = f
def __call__(self, cls):
for name, m in inspect.getmembers(cls, inspect.ismethod):
setattr(cls, name, self.f(m))
return cls
@trace(log)
class X(object):
def first_x_method(self):
print 'doing first_x_method stuff...'
def second_x_method(self):
print 'doing second_x_method stuff...'
x = X()
x.first_x_method()
x.second_x_method()
21
除非有特别的理由要用类来做装饰器,否则我觉得用函数来定义装饰器通常更简单。
下面是创建一个类装饰器 trace
的方法,它会给类的所有方法加上 log
装饰器:
import inspect
def log(func):
def wrapped(*args, **kwargs):
try:
print("Entering: [%s] with parameters %s" % (func.__name__, args))
try:
return func(*args, **kwargs)
except Exception as e:
print('Exception in %s : %s' % (func.__name__, e))
finally:
print("Exiting: [%s]" % func.__name__)
return wrapped
def trace(cls):
# https://stackoverflow.com/a/17019983/190597 (jamylak)
for name, m in inspect.getmembers(cls, lambda x: inspect.isfunction(x) or inspect.ismethod(x)):
setattr(cls, name, log(m))
return cls
@trace
class X(object):
def first_x_method(self):
print('doing first_x_method stuff...')
def second_x_method(self):
print('doing second_x_method stuff...')
x = X()
x.first_x_method()
x.second_x_method()
结果是:
Entering: [first_x_method] with parameters (<__main__.X object at 0x7f19e6ae2e80>,)
doing first_x_method stuff...
Exiting: [first_x_method]
Entering: [second_x_method] with parameters (<__main__.X object at 0x7f19e6ae2e80>,)
doing second_x_method stuff...
Exiting: [second_x_method]