Dynamically add a decorator to class
decorator, pyqt, pyqt4, python, python-decorators
Solution
Decorators are nothing more than callables that are applied automatically. To apply it manually, replace the class with the return value of the decorator:
import somemodule
somemodule.someclass = debug_signals(somemodule.someclass)
This replaces the `somemodule.someclass` name with the return value of `debug_signals`, which we passed the original `somemodule.someclass` class.
Problem
I have a rather large and involved decorator to debug PyQt signals that I want to dynamically add to a class. Is there a way to add a decorator to a class dynamically? I might be approaching this problem from the wrong angle, so here is what I want to accomplish. Goal - I have a decorator that will discover/attach to all pyqt signals in a class and print debug when those signals are emitted. - This decorator is great for debugging a single class' signals. However, there might be a time when I would like to attach to ALL my signals in an application. This could be used to see if I'm emitting signals at unexpected times, etc. - I'd like to dynamically attach this decorator to all my classes that have signals. Possible solutions/ideas I've thought through a few possible solutions so far: - Inheritance: This would be easy if all my classes had the same base class (other than Python's built-in `object` and PyQt's built-in `QtCore.QObject`). I suppose I could just attach this decorator to my base class and everything would workout as expected. However, this is not the case in this particular application. I don't want to change all my classes to have the same base class either. - Monkey-patch Python `object` or `QtCore.QObject`: I don't know how this would work practically. However, in theory could I change one of these base classes' `__init__` to be the `new_init` I define in my decorator? This seems really dangerous and hackish but maybe it's a good way? - Metaclasses: I don't think metaclasses will work in this scenario because I'd have to dynamically add the `__metaclass__` attribute to the classes I want to inject the decorator into. I think this is impossible because to insert this attribute the class must have already been constructed. Thus, whatever metaclass I define won't be called. Is this true? I tried a few variants of metaclass magic but nothing seemed to work. I feel like using metaclasses might be a way to accomplish what I want, but I can't seem to get it working. Again, I might be going about this all wrong. Essentially I want to attach the behavior in my decorator referenced above to all classes in my application (maybe even a list of select classes). Also, I could refactor my decorator if necessary. I don't really care if I attach this behavior with a decorator or another mechanism. I just assumed this decorator already accomplishes what I want for a single class so maybe it was easy to extend.