Last active
June 13, 2017 17:27
-
-
Save nhumrich/ade3d2294fe7b93cf177703c558bf02f to your computer and use it in GitHub Desktop.
metaclass wrapping vs __getattr__
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import functools | |
import inspect | |
from timeit import timeit | |
class Bob: | |
__slots__ = ('a',) | |
def __init__(self): | |
self.a = 5 | |
def say_hello(self): | |
return 'hello' | |
def add(self, b): | |
return self.a + b | |
class MyMeta(type): | |
def __new__(mcls, name, bases, dct): | |
def get_wrapper(meth): | |
def wrapper(self, *args, **kwargs): | |
return self._dispatch_method_call(meth, args, kwargs) | |
return wrapper | |
for attrname in dir(Bob): | |
if attrname.startswith('_') or attrname in dct: | |
continue | |
meth = getattr(Bob, attrname) | |
if not inspect.isfunction(meth): | |
continue | |
wrapper = get_wrapper(meth) | |
wrapper = functools.update_wrapper(wrapper, meth) | |
dct[attrname] = wrapper | |
if '__doc__' not in dct: | |
dct['__doc__'] = Bob.__doc__ | |
return super().__new__(mcls, name, bases, dct) | |
class Alice(metaclass=MyMeta): | |
__slots__ = ('_bob',) | |
def __init__(self, bob): | |
self._bob = bob | |
def _dispatch_method_call(self, meth, args, kwargs): | |
return meth(self._bob, *args, **kwargs) | |
class Alice2: | |
__slots__ = ('_bob',) | |
def __init__(self, bob): | |
self._bob = bob | |
def __getattr__(self, item): | |
return getattr(self._bob, item) | |
def with_alice(): | |
bob = Bob() | |
alice = Alice(bob) | |
alice.say_hello() | |
alice.add(3) | |
def with_alice2(): | |
bob = Bob() | |
alice = Alice2(bob) | |
alice.say_hello() | |
alice.add(3) | |
print('with metaclass:', timeit(with_alice)) | |
print('with __getattr__', timeit(with_alice2)) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment