If you really need this to be fast, the fastest option is to monkeypatch yourself at initialization:
def __init__(self, wrappee):
for name, value in inspect.getmembers(wrappee, callable):
if not hasattr(self, name):
setattr(self, name, value)
This will give your Wrapper
instances normal data attributes whose values are bound methods of the Wrappee
. That should be blazingly fast. Is it?
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
So, copying bound methods has a 3% cost (not sure why it even has that much…). Anything more dynamic than this would have to pull attributes from self.wrapper
, which has a minimum 66% overhead. The usual __getattr__
solution has 471% overhead (and adding unnecessary extra stuff to it can only make it slower).
So, that sounds like an open and shut win for the bound-methods hack, right?
Not necessarily. That 471% overhead is still only 700 nanoseconds. Is that really going to make a difference in your code? Probably not unless it's being used inside a tight loop—in which case you're almost certainly going to want to copy the method to a local variable anyway.
And there are a lot of downsides of this hack. It's not the "one obvious way to do it". It won't work for special methods that aren't looked up on the instance dict. It's statically pulling the attributes off o2
, so if you create any new ones later, o1
won't be proxying to them (try building a dynamic chain of proxies this way…). It wastes a lot of memory if you have a lot of proxies. It's slightly different between Python 2.x and 3.x (and even within the 2.x and 3.x series, if you rely on inspect
), while __getattr__
has very carefully been kept the same from 2.3 up to the present (and in alternate Python implementations, too). And so on.
If you really need the speed, you may want to consider a hybrid: a __getattr__
method that caches proxied methods. You can even do it in two stages: something that's called once, you cache the unbound method in a class attribute and bind it on the fly; if it's then called repeatedly, you cache the bound method in an instance attribute.