I'm working with quite a large OOP code-base, and I'd like to inject some tracing/logging. The easiest way to do this would be to introduce a decorator around certain methods on some base classes, but unfortunately decorators aren't inherited.
I did try something like the following:
def trace(fn):
def wrapper(instance, *args, **kwargs):
result = fn(instance, *args, **kwargs)
# trace logic...
return result
return wrapper
class BaseClass(object):
def __init__(self, ...):
...
self.__call__ = trace(self.__call__) # line added to end of method
...and while the __call__ method is wrapped (which I can see from printing the instance information to the console) the wrapper function isn't executed as expected.
I also looked briefly at using a metaclass based on this answer, but it instantly breaks other parts of the system that use introspection, so I think that's a no-go.
Is there any other way I can force the application of these decorators around the __call__ method of classes that inherit from BaseClass?
解决方案
Why would metaprogramming mess up introspection? Perhaps you are not using it correctly? Try this (assuming Python2.x):
class MyMeta(type):
def __new__(mcl, name, bases, nmspc):
if "__call__" in nmspc:
nmspc["__call__"] = trace(nmspc["__call__"])
return super(MyMeta, mcl).__new__(mcl, name, bases, nmspc)
class BaseClass(object):
__metaclass__ = MyMeta
You can then simply inherit from BaseClass and __call__ will get wrapped automatically.
I'm not sure what kind of introspection would break that. Unless BaseClass actually does not inherit from object but from something that implements its own meta?? But you can deal with that case as well by forcing MyMeta to inherit from that parent's meta (instead of type).