Python(3.5)のコンテキストマネージャを使用しようとすると、次の2つのシナリオで動作が異なります。コンテキストマネージャと組み合わせて適切なシャットダウンプロシージャを使用することで、私のスレッドプログラムの例外を正常に処理しようとしていますが、2番目のケースで動作するようにはできません。 。一度start
(内部run
を呼び出すthreading.Thread
親クラスによって提供される方法)で開始コンテキストクラスとコンテキストマネージャのメソッドデコレータをPythonで使用するときの動作が異なります
import threading
class Job(threading.Thread):
def run(self):
self.active = True
while self.active:
continue
def stop(self):
self.active = False
、それを停止することができます。両方のケースに共通する
はスレッド使用し、一般的な「仕事」作業ですstop
に電話してください。私はそれが次のコードを使用して実行
class Context(object):
def __init__(self):
self.active = False
def __enter__(self):
print("Entering context")
self.job = Job()
self.job.start()
return self.job
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting context")
self.job.stop()
self.job.join()
print("Job stopped")
:Pythonのwith
声明サポートを利用するように
私はこれを行うことを試みた最初の方法は、__enter__
を内蔵し、__exit__
メソッドを使用していた
with Context():
while input() != "stop":
continue
これは、ユーザーが「停止」と入力してEnterを押すまで待機します。このループ中にユーザーが代わりにKeyboardInterrupt
を作成するためにCtrl+C
を押すと、__exit__
メソッドがまだ呼び出されます
from contextlib import contextmanager
@contextmanager
def job_context():
print("Entering context")
job = Job()
job.start()
yield job
print("Exiting context")
job.stop()
job.join()
print("Job stopped")
:私はこれを実行しようとしました
Entering context
^CExiting context
Job stopped
Traceback (most recent call last):
File "tmp2.py", line 48, in <module>
while input() != "stop":
KeyboardInterrupt
第二の方法は@contextmanager
デコレータを使用して関数を作成することでした
私は再びwith
文を使用して、それを実行します。
with job_context():
while input() != "stop":
continue
しかし、私は実行しますそしてCtrl+C
を押すと、最初の例の__exit__
メソッドに相当するyield
のコードが実行されません。代わりに、Pythonスクリプトは無限ループで実行され続けます。
Entering context
^CTraceback (most recent call last):
File "tmp2.py", line 42, in <module>
while input() != "stop":
KeyboardInterrupt
^CException ignored in: <module 'threading' from '/usr/lib/python3.5/threading.py'>
Traceback (most recent call last):
File "/usr/lib/python3.5/threading.py", line 1288, in _shutdown
t.join()
File "/usr/lib/python3.5/threading.py", line 1054, in join
self._wait_for_tstate_lock()
File "/usr/lib/python3.5/threading.py", line 1070, in _wait_for_tstate_lock
elif lock.acquire(block, timeout):
KeyboardInterrupt
あなたは、私が割り込みを作成するためにCtrl+C
を押し^C
シンボルを見ることができます。プログラムを停止するには、私はCtrl+C
にyield
後のコードが実行されていないこの時点で二回目を押す必要があります。最初のケースで__exit__
に相当するシャットダウンコードを実行しない2番目のケースでは何が違うのですか? the documentation当たり
!ありがとうございました。 yieldコマンドを使用したメソッドで例外がスローされるのは、直感的ではありません。確かに、例外が生成された場所でスローされるべきですか? – Sean
「生産された場所」*は何を意味しますか? – jonrsharpe
'KeyboardException'はメインループで発生しますので、ジェネレータでリレイズされるのは奇妙です。 – Sean