有许多不同的方法可以实现。我将展示如何通过 元类、类装饰器和继承来完成。
通过更改元类实现
import functools
class Logger(type):
@staticmethod
def _decorator(fun):
@functools.wraps(fun)
def wrapper(*args, **kwargs):
print(fun.__name__, args, kwargs)
return fun(*args, **kwargs)
return wrapper
def __new__(mcs, name, bases, attrs):
for key in attrs.keys():
if callable(attrs[key]):
fun = attrs[key]
attrs[key] = Logger._decorator(fun)
return super().__new__(mcs, name, bases, attrs)
class A(metaclass=Logger):
def __init__(self):
self.some_val = "some_val"
def method_first(self, a, b):
print(a, self.some_val)
def another_method(self, c):
print(c)
@staticmethod
def static_method(d):
print(d)
b = A()
b.method_first(5, b="Here should be 5")
b.method_first(6, b="Here should be 6")
b.another_method(7)
b.static_method(7)
此外,我将展示两种方法如何实现它而不改变类的元信息(通过类装饰器和类继承)。第一种方法是通过类装饰器put_decorator_on_all_methods
来接受装饰器,以包装类的所有成员可调用对象。
def logger(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
print(f.__name__, args, kwargs)
return f(*args, **kwargs)
return wrapper
def put_decorator_on_all_methods(decorator, cls=None):
if cls is None:
return lambda cls: put_decorator_on_all_methods(decorator, cls)
class Decoratable(cls):
def __init__(self, *args, **kargs):
super().__init__(*args, **kargs)
def __getattribute__(self, item):
value = object.__getattribute__(self, item)
if callable(value):
return decorator(value)
return value
return Decoratable
@put_decorator_on_all_methods(logger)
class A:
def method(self, a, b):
print(a)
def another_method(self, c):
print(c)
@staticmethod
def static_method(d):
print(d)
b = A()
b.method(5, b="Here should be 5")
b.method(6, b="Here should be 6")
b.another_method(7)
b.static_method(8)
最近,我遇到了同样的问题,但我无法在类上放置装饰器或以任何其他方式更改它,除非我只能通过继承来添加这种行为(如果您可以随意更改代码库,我不确定这是否是最佳选择)。
在这里,Logger
类强制其子类的所有可调用成员编写有关它们调用的信息,请参见下面的代码。
class Logger:
def _decorator(self, f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
print(f.__name__, args, kwargs)
return f(*args, **kwargs)
return wrapper
def __getattribute__(self, item):
value = object.__getattribute__(self, item)
if callable(value):
decorator = object.__getattribute__(self, '_decorator')
return decorator(value)
return value
class A(Logger):
def method(self, a, b):
print(a)
def another_method(self, c):
print(c)
@staticmethod
def static_method(d):
print(d)
b = A()
b.method(5, b="Here should be 5")
b.method(6, b="Here should be 6")
b.another_method(7)
b.static_method(7)
更抽象地说,您可以根据某些装饰器实例化基类。
def decorator(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
print(f.__name__, args, kwargs)
return f(*args, **kwargs)
return wrapper
class Decoratable:
def __init__(self, dec):
self._decorator = dec
def __getattribute__(self, item):
value = object.__getattribute__(self, item)
if callable(value):
decorator = object.__getattribute__(self, '_decorator')
return decorator(value)
return value
class A(Decoratable):
def __init__(self, dec):
super().__init__(dec)
def method(self, a, b):
print(a)
def another_method(self, c):
print(c)
@staticmethod
def static_method(d):
print(d)
b = A(decorator)
b.method(5, b="Here should be 5")
b.method(6, b="Here should be 6")
b.another_method(7)
b.static_method(7)