线程类中__init__的对面?

问题描述 投票:0回答:4

我知道当您创建像

__init__()
这样的类时,
newThread = MyThread(property)
会自动调用,而
run()
newthread.start()
触发。我正在寻找的是在线程终止之前自动调用的东西,所以我不必在每个 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
python python-multithreading
4个回答
9
投票

实现此目的的一种方法是使

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!
    

3
投票

Python邮件列表所述,__del__

不应该被认为是相反的,但您可以使用
with
语法,这是一个
上下文管理器

你不能确定一个对象的析构函数(

__del__()

)会永远
  叫做。如果你想确保一个特定的对象得到
  处理后,一种方法是 with- 语法。

或者您也可以查看 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
投票
如果您要解决的问题是您不想向每个

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 不提供与此等效的内置功能,如果您正在寻找的话。


0
投票
假设 EntryExit 是一个声明了 __entry__(...) 和 __exit__(..) 以及一个函数(...) 的类,以下将不起作用:

with EntryExit() as e_e: # this fails because e_e is None print(e_e.function())
但这行得通:

with (e_e := EntryExit()): print(e_e.function())
针对 3.12.0a6 进行测试

© www.soinside.com 2019 - 2024. All rights reserved.