I understand that __init__()
is called automatically when you create a class like newThread = MyThread(property)
and run()
is triggered by newthread.start()
. What I am looking for is something that is called automatically before a thread terminates, so I don't have to explicitly call self.cleanUp()
before each return statement.
class MyThread(Thread):
def __init__(self, property):
Thread.__init__(self)
self.property = property
def cleanUp(self):
# Clean up here
def run(self):
# Do some stuff
self.cleanUp() # Current work around
return
While __del__() is considered the opposite, there can be issues with when it is called.
__init__() method is called when an object is initialized. And when you do - Thread. __init__(self) , it just just calling the parent class' __init__() method . Like said in comment you can remove it and the functionality should remain same.
You can still instantiate a class that doesn't specify the __init__ method. Leaving it out does not make your class abstract. Please give context to your code. Answers containing code only without explanation and/or comments are not very useful.
def __init__(self, n) -> None: means that __init__ should always return NoneType and it can be quite helpful if you accidentally return something different from None especially if you use mypy or other similar things. But you can ignore it if you prefer the old way to do it. Follow this answer to receive notifications.
One way to do this is by making the Thread
subclass also a context manager. This will effectively make __exit__()
the special method you want triggered.
The following shows what I'm proposing. Note: I renamed the property
argument you were passing the constructor because property
is the name of a Python built-in.
from threading import Thread
import time
TEST_THREAD_EXCEPTION = False # change as desired
class MyThread(Thread):
def __init__(self, attribute):
Thread.__init__(self)
self.attribute = attribute
def cleanup(self):
# Clean up here
print(' cleaning up after thread')
def run(self):
if TEST_THREAD_EXCEPTION:
raise RuntimeError('OOPS!') # force exception
print(' other thread now running...')
time.sleep(2) # Do something...
def __enter__(self):
try:
self.run()
except Exception as exc:
print('Error: {} exception raised by thread'.format(exc))
raise # reraise the exception
return self
def __exit__(self, *args):
self.cleanup()
print('main thread begins execution')
with MyThread('hello') as thread:
print('doing other things in main thread while other thread is running')
print('main thread continuing...')
Output:
main thread begins execution
other thread now running...
doing other things in main thread while other thread is running
cleaning up after thread
main thread continuing on...
If you change TEST_THREAD_EXCEPTION
to True
, cleanup()
won't be called since the thread didn't run successfully—although you could change that if you wished, but may also need to ensure that it doesn't get called twice. Here's what the code above does in that case:
main thread begins execution
Error: OOPS! exception raised by thread
Traceback (most recent call last):
File "opposite_init.py", line 37, in <module>
with MyThread('hello') as thread:
File "opposite_init.py", line 27, in __enter__
self.run()
File "opposite_init.py", line 21, in run
raise RuntimeError('OOPS!') # force exception
RuntimeError: OOPS!
As stated in the Python mailing list, __del__
shouldn't be considered the opposite, but you can use the with
syntax, which is a context manager
you cannot be sure that an object's destructor (
__del__()
) will ever be called. If you want to make sure that a particular object gets processed, one approach is the with- syntax.
Or you can also look into the try...finally clause, in which the finally statement will always get run.
class MyThread(Thread):
def __init__(self, property):
Thread.__init__(self)
self.property = property
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
print('starting cleanup')
# Clean up here
def run(self):
# Do some stuff
return
# not now you can call it like this:
with MyThread("spam") as spam:
print("The thread is running")
# you can also do stuff here
You can use the try...finally clause like so:
class MyThread(Thread):
def __init__(self, property):
Thread.__init__(self)
self.property = property
def cleanUp(self):
# Clean up here
print('starting cleanup')
def run(self):
# Do some stuff
return
try:
spam = MyThread('spam')
print('The thread is running')
finally:
spam.cleanUp()
If the problem you're trying to solve is that you don't want to add code to each of your run()
methods to call your cleanup function, then I'd suggest making a custom subclass of Thread
which does that for you. Something like this, perhaps:
class CleanupThread(Thread):
def cleanup(self):
# Override this method in your subclasses to do cleanup
pass
def run2(self):
# Override this method in your subclasses instead of run()
pass
def run(self):
# Do *not* override this in your subclasses. Override run2() instead.
try:
self.run2()
finally:
self.cleanup()
Of course, you're free to rename run2
to something that makes sense for you.
Python does not offer a built-in equivalent of this, if that's what you're looking for.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With