可以作为实例方法调用吗?
假设我们有一个元类 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
演化而来的。 所以我尝试将两者用作元类,但也没有运气。 情况可能是他们作为元类有特殊要求,但目前我们似乎处于未记录的领域。
有任何想法吗?
Let's say we've got a metaclass CallableWrappingMeta
which walks the body of a new class, wrapping its methods with a class, 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!'
Our dummy wrapper just prints the arguments as they come in. But you'll notice something conspicuous: the method isn't passed the instance-object receiver, because even though InstanceMethodWrapper
is callable, it is not treated as a function for the purpose of being converted to an instance method during class creation (after our metaclass is done with it).
A potential solution is to use a decorator instead of a class to wrap the methods -- that function will become an instance method. But in the real world, InstanceMethodWrapper
is much more complex: it provides an API and publishes method-call events. A class is more convenient (and more performant, not that this matters much).
I also tried some dead-ends. Subclassing types.MethodType
and types.UnboundMethodType
didn't go anywhere. A little introspection, and it appears they decend from type
. So I tried using both as a metaclass, but no luck there either. It might be the case that they have special demands as a metaclass, but it seems we're in undocumented territory at this point.
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
只需使用
__get__
来丰富您的InstanceMethodWrapper
类(它完全可以返回 self
)——也就是说,将该类变成 descriptor 类型,因此它的实例是描述符对象。 请参阅http://users.rcn.com/python/download/Descriptor.htm 了解背景和详细信息。顺便说一句,如果您使用的是 Python 2.6 或更高版本,请考虑使用类装饰器而不是元类——我们添加类装饰器正是因为如此多的元类仅用于此类装饰目的,并且装饰器使用起来确实要简单得多。
Just enrich you
InstanceMethodWrapper
class with a__get__
(which can perfectly well justreturn self
) -- that is, make that class into a descriptor type, so that its instances are descriptor objects. See http://users.rcn.com/python/download/Descriptor.htm for background and details.BTW, if you're on Python 2.6 or better, consider using a class-decorator instead of that metaclass -- we added class decorators exactly because so many metaclasses were being used just for such decoration purposes, and decorators are really much simpler to use.
编辑:我又撒谎了。 函数上的
__?attr__
属性是只读的,但显然在赋值时并不总是抛出AttributeException
异常? 我不知道。 回到原点!编辑:这实际上并不能解决问题,因为包装函数不会将属性请求代理到
InstanceMethodWrapper
。 当然,我可以在装饰器中对__?attr__
属性进行鸭式打孔(duck-punch)——这就是我现在正在做的事情——但这很丑陋。 非常欢迎更好的想法。当然,我立即意识到将一个简单的装饰器与我们的类相结合就可以解决问题:
然后将装饰器添加到元类 Poof 中对
InstanceMethodWrapper
的调用中。 有点倾斜,但有效。
Edit: I lie yet again. The
__?attr__
attributes on functions are readonly, but apparently do not always throw anAttributeException
exception when you assign? I dunno. Back to square one!Edit: This doesn't actually solve the problem, as the wrapping function won't proxy attribute requests to the
InstanceMethodWrapper
. I could, of course, duck-punch the__?attr__
attributes in the decorator--and it is what I'm doing now--but that's ugly. Better ideas are very welcome.Of course, I immediately realized that combining a simple decorator with our classes will do the trick:
Then you add the decorator to the call to
InstanceMethodWrapper
in the metaclass:Poof. A little oblique, but it works.
我猜您正在尝试创建一个元类,用自定义函数包装类中的每个方法。
这是我的版本,我认为稍微不那么倾斜。
I'm guessing you are trying to make a metaclass that wraps every method in the class with a custom function.
Here is my version which I think is a little bit less oblique.
我认为你需要更具体地说明你的问题。 最初的问题讨论了包装函数,但您随后的答案似乎讨论了保留函数属性,这似乎是一个新因素。 如果您更清楚地阐明您的设计目标,可能会更容易回答您的问题。
I think you need to be more specific about your problem. The original question talks about wrapping a function, but your subsequent answer seems to talk about preserving function attributes, which seems to be a new factor. If you spelled out your design goals more clearly, it might be easier to answer your question.