与线程类中的__init__相反

时间:2017-04-14 14:25:23

标签: python

我知道当你创建像newThread = MyThread(property)这样的类并且newthread.start()触发run()时会自动调用__init __()。我正在寻找的是在线程终止之前自动调用的东西,所以我不必在每个return语句之前显式调用self.cleanUp()

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

3 个答案:

答案 0 :(得分:6)

实现此目的的一种方法是使Thread子类也成为context manager。这将有效地使__exit__()成为您想要触发的特殊方法。

以下显示了我提出的建议。注意:我重命名了您传递构造函数的property参数,因为property是Python内置的名称。

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...')

输出:

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...

如果您将TEST_THREAD_EXCEPTION更改为True,则cleanup() 不会被调用,因为线程未成功运行 - 尽管您可能会改变,如果你愿意,但也可能需要确保它不会被调用两次。以下是上述代码在这种情况下的作用:

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!

答案 1 :(得分:2)

正如Python mailing list中所述,__del__不应被视为相反,但您可以使用with语法,即context manager

  

你无法确定对象的析构函数(__del__())是否会永远   叫做。如果要确保特定对象获得   经过处理,一种方法就是语法。

或者您也可以查看try ... finally子句,其中finally语句将始终运行。

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

您可以像这样使用try ... finally子句:

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()

答案 2 :(得分:2)

如果您尝试解决的问题是您不想为每个run()方法添加代码来调用您的清理功能,那么我建议您制作Thread的自定义子类,它可以为您完成。这样的事情,也许是:

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()

当然,您可以自由地将run2重命名为对您有用的内容。

如果您正在寻找的话,Python不会提供相应的内置功能。<​​/ p>