The process of subclassing Python with an initializer

I am trying to create an object as a new process. If I give the initializer to the class, the program shows an error.

Code

import multiprocessing as mp import time class My_class(mp.Process): def __init__(self): self.name = "Hello "+self.name self.num = 20 def run(self): print self.name, "created and waiting for", str(self.num), "seconds" time.sleep(self.num) print self.name, "exiting" if __name__ == '__main__': print 'main started' p1=My_class() p2=My_class() p1.start() p2.start() print 'main exited' 

error

 File "/usr/lib64/python2.7/multiprocessing/process.py", line 120, in start assert self._popen is None, 'cannot start a process twice' AttributeError: 'My_class' object has no attribute '_popen' 

But when the string super(My_class, self).__init__() is inserted into the initializer, the program works fine.

Final constructor:

 def __init__(self): super(My_class, self).__init__() self.name = "Hello "+self.name self.num = 20 

I found this line in a different context and tried it here and the code works fine.

Can anyone explain how the super(My_class, self).__init__() line works in the initializer above?

+7
source share
2 answers

When you add your own __init__() here, you override __init__() in the superclass. However, in the superclass often (as in this case) there are some things that it needs in __init__() . Therefore, you need to either re-create this functionality (for example, initialize _popen , as described in your error, by the way), or call the superclass constructor in your new constructor using super(My_class, self).__init__() (or super().__init__() in Python 3).

+10
source

Well, you don't have _popen in your class.

If _popen was declared at the class level or was a function in mp.Process, then your code will work because it will grab it from the Process namespace.

 class Process(object): _popen = None def __init__(...): #stuff, but not involving _popen 

The statement looks like a guard, and I guess the code looks something like this:

 class Process(object): def __init__(...): #let make sure that we don't open twice self._popen = None 

Now, in this case, _popen is installed only in the instance, and not in the Process class. But in order for it to be installed, you need to execute this mp.Process .__ init__ code.

Your code will work fine if you called the ".__ init__ Process", which you did not initially do.

Instead of using Super, you can call it

 class My_Class(mp.Process): def __init__(self): # mp.Process.__init__(self) ....do your stuff.... 

this is what i did and it works great. But it breaks if you change the inheritance to say My_Class (mp.AnotherProcessType). In this case, any calls to mp.Process.somefunc (), and not just __init__, must be adjusted manually.

super (My_Class, self) .init () ultimately does the same thing in this case, but is a more reliable way to do homework to call mp.Process .__ init __.

Sometimes you can refuse to call init for the ancestor of the Python class. But it all depends on whether there is an initialization code that needs to be run. And in this case, it seems that there is.

Also, if you did not have __init__ in your class, you also do not have to worry, mp.Process .__ init__ will be called automatically. But having your own __init__ basically says: "I will do my own initialization, thank you very much." It is up to your code to explicitly delegate some work back to the ancestor class, if necessary.

ps don't worry, I find super (xxx, self) .somefunc () a bit non-pythonic obscure. But it works.

+3
source

Source: https://habr.com/ru/post/982973/


All Articles