假设我们有一个元类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
。所以我尝试将两者都用作元类,但也没有运气。情况可能是他们作为元类有特殊要求,但此时我们似乎处于无证领域。
有什么想法吗?
答案 0 :(得分:3)
只需使用InstanceMethodWrapper
(完全可以__get__
)来丰富return self
课程 - 也就是说,将该课程设为描述符类型,以便它的实例是描述符对象。有关背景和详细信息,请参阅http://users.rcn.com/python/download/Descriptor.htm。
答案 1 :(得分:0)
编辑:我再次撒谎。函数的__?attr__
属性是只读的,但是在分配时显然并不总是抛出AttributeException
异常?我不知道。回到原点!
编辑:这实际上并没有解决问题,因为包装功能不会将属性请求代理到InstanceMethodWrapper
。当然,我可以在装饰器中点击__?attr__
属性 - 而这正是我现在正在做的 - 但那很难看。更好的想法是非常受欢迎的。
当然,我立刻意识到将一个简单的装饰器与我们的类结合起来就可以了:
def methodize(method, callable):
"Circumvents the fact that callables are not converted to instance methods."
@wraps(method)
def wrapper(*args, **kw):
return wrapper._callable(*args, **kw)
wrapper._callable = callable
return wrapper
然后将装饰器添加到元类中对InstanceMethodWrapper
的调用:
cls_dict[k] = methodize(v, InstanceMethodWrapper(v))
噗。有点倾斜,但它有效。
答案 2 :(得分:0)
我猜你正在尝试使用自定义函数创建一个包装类中每个方法的元类。
这是我的版本,我认为它有点不那么倾斜。
import types
class CallableWrappingMeta(type):
def __new__(mcls, name, bases, cls_dict):
instance = type.__new__(mcls, name, bases, cls_dict)
for k in dir(instance):
v = getattr(instance, k)
if isinstance(v, types.MethodType):
setattr(instance, k, instanceMethodWrapper(v))
return instance
def instanceMethodWrapper(function):
def customfunc(*args, **kw):
print "instanceMethodWrapper(*%r, **%r )" % (args, kw)
return function(*args, **kw)
return customfunc
class Bar(object):
__metaclass__ = CallableWrappingMeta
def method(self, a, b):
print a,b
a = Bar()
a.method("foo","bar")
答案 3 :(得分:0)
我认为你需要更具体地解决你的问题。最初的问题涉及包装函数,但你后来的回答似乎是讨论保留函数属性,这似乎是一个新因素。如果您更清楚地阐明您的设计目标,则可能更容易回答您的问题。