如果你真的需要这个速度很快,最快的选择是在初始化时给自己打补丁:
def __init__(self, wrappee):
for name, value in inspect.getmembers(wrappee, callable):
if not hasattr(self, name):
setattr(self, name, value)
这将为您的Wrapper 实例提供普通数据属性,其值是Wrappee 的绑定方法。那应该非常快。是吗?
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
所以,复制绑定方法有 3% 的成本(不知道为什么它甚至有那么多……)。任何比这更动态的都必须从self.wrapper 中提取属性,这至少有 66% 的开销。通常的__getattr__ 解决方案有 471% 的开销(添加不必要的额外内容只会使其变慢)。
所以,这听起来像是对绑定方法黑客的公开和封闭的胜利,对吧?
不一定。那 471% 的开销仍然只有 700 纳秒。这真的会对您的代码产生影响吗?除非在紧密循环中使用,否则可能不会——在这种情况下,您几乎肯定会想要将方法复制到局部变量中。
而且这种 hack 有很多缺点。这不是“一种明显的方法”。它不适用于未在实例字典上查找的特殊方法。它静态地从o2 中提取属性,因此如果您稍后创建任何新属性,o1 将不会代理它们(尝试以这种方式构建动态代理链......)。如果你有很多代理,它会浪费很多内存。 Python 2.x 和 3.x 之间略有不同(甚至在 2.x 和 3.x 系列中,如果您依赖 inspect),而 __getattr__ 从 2.3 到 2.3 都非常小心地保持不变现在(以及在其他 Python 实现中也是如此)。以此类推。
如果您真的需要速度,您可能需要考虑混合:缓存代理方法的__getattr__ 方法。您甚至可以分两个阶段进行:调用一次,将未绑定的方法缓存在类属性中并动态绑定它;如果它随后被重复调用,则将绑定的方法缓存在实例属性中。