<p>如果您真的需要加快速度,那么最快的方法是在初始化时自己进行monkeypatch:</p>
<pre><code>def __init__(self, wrappee):
for name, value in inspect.getmembers(wrappee, callable):
if not hasattr(self, name):
setattr(self, name, value)
</code></pre>
<p>这将为您的<code>Wrapper</code>实例提供常规数据属性,这些属性的值是<code>Wrappee</code>的绑定方法。那应该非常快。它是?</p>
<pre><code>class WrapperA(object):
def __init__(self, wrappee):
self.wrappee = wrappee
for name, value in inspect.getmembers(wrappee, callable):
if not hasattr(self, name):
setattr(self, name, value)
class WrapperB(object):
def __init__(self, wrappee):
self.wrappee = wrappee
def __getattr__(self, name):
return getattr(self.wrappee, name)
In [1]: %run wrapper
In [2]: o2 = Wrappee()
In [3]: o1a = WrapperA(o2)
In [4]: o1b = WrapperB(o2)
In [5]: %timeit o2.bar()
10000000 loops, best of 3: 154 ns per loop
In [6]: %timeit o1a.bar()
10000000 loops, best of 3: 159 ns per loop
In [7]: %timeit o1b.bar()
1000000 loops, best of 3: 879 ns per loop
In [8]: %timeit o1b.wrapper.bar()
1000000 loops, best of 3: 220 ns per loop
</code></pre>
<p>所以,复制绑定的方法有3%的成本(不知道为什么它甚至有那么多…)。任何比这更动态的操作都必须从<code>self.wrapper</code>中提取属性,这至少有66%的开销。通常的<code>__getattr__</code>解决方案有471%的开销(向它添加不必要的额外内容只会使它变慢)。</p>
<p>所以,这听起来像是一个开放和封闭的方法黑客的胜利,对吧?</p>
<p>不一定。471%的开销仍然只有700纳秒。这真的会改变你的代码吗?可能不会,除非它是在一个紧密的循环中使用的,在这种情况下,您几乎肯定要将方法复制到一个局部变量。</p>
<p>而且这次黑客攻击有很多缺点。这不是“一个显而易见的方法”。对于不在实例dict上查找的特殊方法,它将不起作用。它将静态地从<code>o2</code>中提取属性,因此,如果以后创建任何新的属性,<code>o1</code>将不会对它们进行代理(尝试用这种方式构建动态代理链…)。如果你有很多代理,那会浪费很多内存。Python 2.x和3.x(甚至在2.x和3.x系列中,如果您依赖于<code>inspect</code>)的话,两者之间也略有不同,而<code>__getattr__</code>从2.3到现在(以及在其他Python实现中)都非常小心地保持不变。等等。</p>
<p>如果您真的需要这个速度,您可能需要考虑一个混合方法:缓存代理方法的<code>__getattr__</code>方法。您甚至可以分两个阶段执行:一个是调用一次的,将未绑定的方法缓存在类属性中并动态绑定;如果随后重复调用,则将绑定的方法缓存在实例属性中。</p>