比如说,我们有一个元类。CallableWrappingMeta
它走的是一个新类的主体,用一个类来包装它的方法。InstanceMethodWrapper
:
import types
class CallableWrappingMeta(type):
def __new__(mcls, name, bases, cls_dict):
for k, v in cls_dict.iteritems():
if isinstance(v, types.FunctionType):
cls_dict[k] = InstanceMethodWrapper(v)
return type.__new__(mcls, name, bases, cls_dict)
class InstanceMethodWrapper(object):
def __init__(self, method):
self.method = method
def __call__(self, *args, **kw):
print "InstanceMethodWrapper.__call__( %s, *%r, **%r )" % (self, args, kw)
return self.method(*args, **kw)
class Bar(object):
__metaclass__ = CallableWrappingMeta
def __init__(self):
print 'bar!'
我们的虚拟包装器只是在参数进来时打印它们。但是你会注意到一些显眼的东西:该方法并没有传递给实例对象接收器,因为虽然 InstanceMethodWrapper
是可调用的,但在创建类的过程中(在我们的元类完成后),它并没有被当作一个函数来处理,以便转换为一个实例方法。
一个潜在的解决方案是使用一个装饰器而不是一个类来包装方法–该函数将成为一个实例方法。但在现实世界中。InstanceMethodWrapper
要复杂得多:它提供了一个API并发布方法调用事件。一个类更方便(也更有性能,但这不是很重要)。
我还尝试了一些死胡同。子类 types.MethodType
和 types.UnboundMethodType
没有去任何地方。稍微反省一下,他们似乎是从… … type
. 所以我试着把这两个都作为元类使用,但也没有成功。可能是它们作为元类有特殊的需求,但似乎我们现在处于无文档的领域。
有什么想法吗?
解决方案:
只是丰富你 InstanceMethodWrapper
阶级与 __get__
(这完全可以只是 return self
)–也就是说,把这个类变成一个 描述符 类型,所以它的实例是描述符对象。 参见 http:/users.cn.comythondownloadDescriptor.htm。 的背景和细节。
另外,如果你是在Python 2.6或更高版本上,可以考虑使用一个类装饰器来代替那个元类–我们添加类装饰器正是因为有太多的元类被用于这种装饰目的,而装饰器的使用确实要简单得多。