假设我们有一个元类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
开始堕落。所以我试着用这两种方法作为元类,但也没什么好运气的。也许他们对元类有特殊的要求,但现在看来我们已经进入了无文档的领域。在
有什么想法吗?在
我猜你是在尝试创建一个元类,用一个自定义函数包装类中的每个方法。在
这是我的版本,我觉得不那么偏激。在
编辑:我又撒谎了。函数的
__?attr__
属性是只读的,但显然在赋值时并不总是抛出AttributeException
异常?我不知道。回到原点!在Edit:这并不能真正解决问题,因为包装函数不会将属性请求代理到
InstanceMethodWrapper
。当然,我可以在decorator中对__?attr__
属性进行打孔——这就是我现在所做的——但这很难看。更好的主意是非常受欢迎的。在当然,我马上意识到,将一个简单的decorator与我们的类结合起来就可以做到:
然后将decorator添加到元类中对
^{pr2}$InstanceMethodWrapper
的调用:噗。有点不对劲,但很管用。在
只需使用一个
__get__
(它可以很好地return self
)来充实你的InstanceMethodWrapper
也就是说,把这个类变成一个描述符类型,这样它的实例就是描述符对象。有关背景和详细信息,请参见http://users.rcn.com/python/download/Descriptor.htm。在顺便说一句,如果您使用的是Python2.6或更高版本,请考虑使用一个类decorator而不是那个元类——我们添加类decorator正是因为有太多的元类被用于这样的装饰目的,而decorator的使用真的要简单得多。在
相关问题 更多 >
编程相关推荐