Call input function after __init__ with decorator

I am trying to find a better way to create a class decorator that does the following:

  • Inserts several functions into a decorated class
  • Makes a call to one of these functions AFTER the decorated class' __init__ is called

For now, I just keep a reference to the 'original' __init__ method and replace it with my __init__ , which calls the original and my extra function. It looks something like this:

 orig_init = cls.__init__ def new_init(self, *args, **kwargs): """ 'Extend' wrapped class' __init__ so we can attach to all signals automatically """ orig_init(self, *args, **kwargs) self._debugSignals() cls.__init__ = new_init 

Is there a better way to "increase" the original __init__ or introduce my call to another location? I really need my self._debugSignals() be called some time after creating the object. I also want this to happen automatically, so I thought there was a good place after __init__ .

Extra difference. decorator notes

Perhaps it is worth mentioning some background of this decorator. You can find the full code here . The decorator point should automatically join any PyQt signals and print when they are emitted. The decorator works great when I decorate my QtCore.QObject subclasses, however, I recently tried to automatically decorate all QObject children .

I would like to have a β€œdebugging” mode in the application where I can automatically print ALL signals just to make sure that everything does what I expect. I'm sure this will lead to TONS debugging, but I still would like to see what happens.

The problem is that my current version of the decorator calls segfault when replacing QtCore.QObject.__init__ . I tried to debug this, but the code is all generated by SIP, with which I have little experience.

So, I was wondering if there is a safer, more pythonic way to input a function call AFTER __init__ and hopefully avoid segfault.

+7
source share
2 answers

Based on this post and this answer , an alternative way to do this is through a custom metaclass . This will work as follows (tested in Python 2.7):

 # define a new metaclass which overrides the "__call__" function class NewInitCaller(type): def __call__(cls, *args, **kwargs): """Called when you call MyNewClass() """ obj = type.__call__(cls, *args, **kwargs) obj.new_init() return obj # then create a new class with the __metaclass__ set as our custom metaclass class MyNewClass(object): __metaclass__ = NewInitCaller def __init__(self): print "Init class" def new_init(self): print "New init!!" # when you create an instance a = MyNewClass() >>> Init class >>> New init!! 

The basic idea is as follows:

  • when you call MyNewClass() , it searches for a metaclass, detects that you defined NewInitCaller

  • The metaclass __call__ function is __call__ .

  • This function creates an instance of MyNewClass using type ,

  • The instance starts its own __init__ (print "Init class").

  • The meta class then calls the instance's new_init function.

+6
source

Here is a solution for Python 3.x, based on this post, accepted answer . Also see PEP 3115 for reference, I think the rationale is an interesting read.

Changes in the above example are shown with comments; the only real change is the definition of the metaclass, all other trivial modifications of 2to3.

 # define a new metaclass which overrides the "__call__" function class NewInitCaller(type): def __call__(cls, *args, **kwargs): """Called when you call MyNewClass() """ obj = type.__call__(cls, *args, **kwargs) obj.new_init() return obj # then create a new class with the metaclass passed as an argument class MyNewClass(object, metaclass=NewInitCaller): # added argument # __metaclass__ = NewInitCaller this line is removed; would not have effect def __init__(self): print("Init class") # function, not command def new_init(self): print("New init!!") # function, not command # when you create an instance a = MyNewClass() >>> Init class >>> New init!! 
0
source

All Articles