我知道当您创建像
__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
实现此目的的一种方法是使
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!
Python邮件列表所述,__del__
不应该被认为是相反的,但您可以使用
with
语法,这是一个上下文管理器
你不能确定一个对象的析构函数(或者您也可以查看 try...finally 子句,其中 finally 语句将始终运行。
__del__()
)会永远 叫做。如果你想确保一个特定的对象得到 处理后,一种方法是 with- 语法。
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()
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 不提供与此等效的内置功能,如果您正在寻找的话。
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 进行测试