我正在寻找将方法调用从对象(包装器)传递到对象(包装器)的成员变量的方法。可能有许多方法需要外部化,因此在将方法添加到wrappee时不更改包装器的接口的方法将非常有用。
class Wrapper(object)
def __init__(self, wrappee):
self.wrappee = wrappee
def foo(self):
return 42
class Wrappee(object):
def bar(self):
return 12
o2 = Wrappee()
o1 = Wrapper(o2)
o1.foo() # -> 42
o1.bar() # -> 12
o1.<any new function in Wrappee>() # call directed to this new function
如果这个调用重定向是“快速的”(相对于直接调用,即不增加太多开销),那就太好了。
如果您真的需要加快速度,那么最快的方法是在初始化时自己进行monkeypatch:
这将为您的
Wrapper
实例提供常规数据属性,这些属性的值是Wrappee
的绑定方法。那应该非常快。它是?所以,复制绑定的方法有3%的成本(不知道为什么它甚至有那么多…)。任何比这更动态的操作都必须从
self.wrapper
中提取属性,这至少有66%的开销。通常的__getattr__
解决方案有471%的开销(向它添加不必要的额外内容只会使它变慢)。所以,这听起来像是一个开放和封闭的方法黑客的胜利,对吧?
不一定。471%的开销仍然只有700纳秒。这真的会改变你的代码吗?可能不会,除非它是在一个紧密的循环中使用的,在这种情况下,您几乎肯定要将方法复制到一个局部变量。
而且这次黑客攻击有很多缺点。这不是“一个显而易见的方法”。对于不在实例dict上查找的特殊方法,它将不起作用。它将静态地从
o2
中提取属性,因此,如果以后创建任何新的属性,o1
将不会对它们进行代理(尝试用这种方式构建动态代理链…)。如果你有很多代理,那会浪费很多内存。Python 2.x和3.x(甚至在2.x和3.x系列中,如果您依赖于inspect
)的话,两者之间也略有不同,而__getattr__
从2.3到现在(以及在其他Python实现中)都非常小心地保持不变。等等。如果您真的需要这个速度,您可能需要考虑一个混合方法:缓存代理方法的
__getattr__
方法。您甚至可以分两个阶段执行:一个是调用一次的,将未绑定的方法缓存在类属性中并动态绑定;如果随后重复调用,则将绑定的方法缓存在实例属性中。有点优雅的解决方案是在包装类上创建一个“属性代理”:
所有的魔术都发生在
Wrapper
类的__getattr__
方法上,该方法将尝试访问Wrapper
实例上的方法或属性,如果它不存在,它将尝试使用包装的方法或属性。如果试图访问两个类中都不存在的属性,则会得到以下结果:
相关问题 更多 >
编程相关推荐