Michael Foord的Voidspace博客在一篇题为A Method Decorating Metaclass的文章中描述了一种优雅的方法,该文章介绍了什么是元类以及如何使用它们。将其稍微简化并应用到您的情况中,结果是:from types import FunctionType
from functools import wraps
def wrapper(method):
@wraps(method)
def wrapped(*args, **kwrds):
# ...
return wrapped
class MetaClass(type):
def __new__(meta, classname, bases, classDict):
newClassDict = {}
for attributeName, attribute in classDict.items():
if isinstance(attribute, FunctionType):
# replace it with a wrapped version
attribute = wrapper(attribute)
newClassDict[attributeName] = attribute
return type.__new__(meta, classname, bases, newClassDict)
class MyClass(object):
__metaclass__ = MetaClass # wrap all the methods
def method1(self, ...):
# ...etc ...
在Python中,函数/方法装饰器只是函数包装器加上一些语法糖,使使用它们更容易(而且更漂亮)。
Python 3兼容性更新
前面的代码使用了Python2.x元类语法,为了在Python3.x中使用,需要对其进行翻译,但是在前面的版本中它将不再工作。这意味着它需要使用:class MyBase(metaclass=MetaClass)
...
而不是:class MyBase(object):
__metaclass__ = MetaClass"
...
如果需要,可以编写同时兼容Python2.x和3.x的代码,但这样做需要使用稍微复杂一点的技术,动态创建继承所需元类的新基类,从而避免由于Python的两个版本之间的语法差异而导致的错误。这基本上就是Benjamin Peterson的six模块的^{}函数所做的。from types import FunctionType
from functools import wraps
def wrapper(method):
@wraps(method)
def wrapped(*args, **kwrds):
print('{!r} executing'.format(method.__name__))
return method(*args, **kwrds)
return wrapped
class MetaClass(type):
def __new__(meta, classname, bases, classDict):
newClassDict = {}
for attributeName, attribute in classDict.items():
if isinstance(attribute, FunctionType):
# replace it with a wrapped version
attribute = wrapper(attribute)
newClassDict[attributeName] = attribute
return type.__new__(meta, classname, bases, newClassDict)
def with_metaclass(meta):
""" Create an empty class with the supplied bases and metaclass. """
return type.__new__(meta, "TempBaseClass", (object,), {})
if __name__ == '__main__':
# Inherit metaclass from a dynamically-created base class.
class MyClass(with_metaclass(MetaClass)):
@staticmethod
def a_static_method():
pass
@classmethod
def a_class_method(cls):
pass
def a_method(self):
pass
instance = MyClass()
instance.a_static_method() # Not decorated.
instance.a_class_method() # Not decorated.
instance.a_method() # -> 'a_method' executing