'최종'은 항상 파이썬에서 실행됩니까?
파이썬에서 가능한 마지막 시도 블록에 대해 finally
블록이 항상 실행될 것이라고 보장 됩니까?
예를 들어, except
블록 에있는 동안 돌아 온다고 가정 해 봅시다 .
try:
1/0
except ZeroDivisionError:
return
finally:
print("Does this code run?")
아니면 내가 다시 올릴 수 있습니다 Exception
:
try:
1/0
except ZeroDivisionError:
raise
finally:
print("What about this code?")
테스트 결과 finally
위의 예제에서 실행되는 것으로 나타 났지만 생각하지 않은 다른 시나리오가 있다고 생각합니다.
finally
파이썬에서 블록이 실행되지 않는 시나리오가 있습니까?
"보장"은 그 어떤 finally
가치의 구현보다 훨씬 강한 단어 입니다. 무엇을 보장하는 것은 실행이 전체의 흘러 경우이다 try
- finally
구조, 그것이 통과하게 finally
그렇게 할 수 있습니다. 보장되지 않는 것은 실행이 try
- 밖으로 흘러 나간다는 것입니다 finally
.
finally
생성기 또는 비동기 코 루틴의 A 는 객체가 절대로 실행되지 않으면 실행되지 않을 수 있습니다 . 일어날 수있는 많은 방법이 있습니다. 여기 하나 있습니다 :def gen(text): try: for line in text: try: yield int(line) except: # Ignore blank lines - but catch too much! pass finally: print('Doing important cleanup') text = ['1', '', '2', '', '3'] if any(n > 1 for n in gen(text)): print('Found a number') print('Oops, no cleanup.')
이 예제는 약간 까다 롭습니다. 제너레이터가 가비지 수집 될 때, 파이썬
finally
은GeneratorExit
예외 를 던져 블록 을 실행하려고 시도 하지만, 여기서 우리는 그 예외를 잡았다가yield
다시 경고를 출력하는 시점에 "제너레이터는 GeneratorExit를 무시했습니다. ")하고 포기합니다. 자세한 내용은 PEP 342 (고급 생성기를 통한 코 루틴) 를 참조하십시오.발전기 나 코 루틴이 결론에 실행되지 않을 수 있습니다 다른 방법은 객체가 바로 (심지어 CPython과에, 가능성이 그, 그래) GC'ed하지 않은 경우 포함, 또는 경우
async with
await
에의__aexit__
경우, 또는 객체await
의 또는yield
A의이야finally
블록. 이 목록은 완전한 것이 아닙니다.finally
데몬 스레드가 아닌 모든 스레드가 먼저 종료되면 데몬 스레드의 A 는 절대 실행되지 않을 수 있습니다 .os._exit
will halt the process immediately without executingfinally
blocks.os.fork
may causefinally
blocks to execute twice. As well as just the normal problems you'd expect from things happening twice, this could cause concurrent access conflicts (crashes, stalls, ...) if access to shared resources is not correctly synchronized.Since
multiprocessing
uses fork-without-exec to create worker processes when using the fork start method (the default on Unix), and then callsos._exit
in the worker once the worker's job is done,finally
andmultiprocessing
interaction can be problematic (example).- A C-level segmentation fault will prevent
finally
blocks from running. kill -SIGKILL
will preventfinally
blocks from running.SIGTERM
andSIGHUP
will also preventfinally
blocks from running unless you install a handler to control the shutdown yourself; by default, Python does not handleSIGTERM
orSIGHUP
.- An exception in
finally
can prevent cleanup from completing. One particularly noteworthy case is if the user hits control-C just as we're starting to execute thefinally
block. Python will raise aKeyboardInterrupt
and skip every line of thefinally
block's contents. (KeyboardInterrupt
-safe code is very hard to write). - If the computer loses power, or if it hibernates and doesn't wake up,
finally
blocks won't run.
The finally
block is not a transaction system; it doesn't provide atomicity guarantees or anything of the sort. Some of these examples might seem obvious, but it's easy to forget such things can happen and rely on finally
for too much.
Yes. Finally always wins.
The only way to defeat it is to halt execution before finally:
gets a chance to execute (e.g. crash the interpreter, turn off your computer, suspend a generator forever).
I imagine there are other scenarios I haven't thought of.
Here are a couple more you may not have thought about:
def foo():
# finally always wins
try:
return 1
finally:
return 2
def bar():
# even if he has to eat an unhandled exception, finally wins
try:
raise Exception('boom')
finally:
return 'no boom'
Depending on how you quit the interpreter, sometimes you can "cancel" finally, but not like this:
>>> import sys
>>> try:
... sys.exit()
... finally:
... print('finally wins!')
...
finally wins!
$
Using the precarious os._exit
(this falls under "crash the interpreter" in my opinion):
>>> import os
>>> try:
... os._exit(1)
... finally:
... print('finally!')
...
$
I'm currently running this code, to test if finally will still execute after the heat death of the universe:
try:
while True:
sleep(1)
finally:
print('done')
However, I'm still waiting on the result, so check back here later.
According to the Python documentation:
No matter what happened previously, the final-block is executed once the code block is complete and any raised exceptions handled. Even if there's an error in an exception handler or the else-block and a new exception is raised, the code in the final-block is still run.
It should also be noted that if there are multiple return statements, including one in the finally block, then the finally block return is the only one that will execute.
Well, yes and no.
What is guaranteed is that Python will always try to execute the finally block. In the case where you return from the block or raise an uncaught exception, the finally block is executed just before actually returning or raising the exception.
(what you could have controlled yourself by simply running the code in your question)
The only case I can imagine where the finally block will not be executed is when the Python interpretor itself crashes for example inside C code or because of power outage.
To really understand how it works, just run these two examples:
try: 1 except: print 'except' finally: print 'finally'
will output
finally
try: 1/0 except: print 'except' finally: print 'finally'
will output
except
finally
I found this one without using a generator function:
import multiprocessing
import time
def fun(arg):
try:
print("tried " + str(arg))
time.sleep(arg)
finally:
print("finally cleaned up " + str(arg))
return foo
list = [1, 2, 3]
multiprocessing.Pool().map(fun, list)
The sleep can be any code that might run for inconsistent amounts of time.
What appears to be happening here is that the first parallel process to finish leaves the try block successfully, but then attempts to return from the function a value (foo) that hasn't been defined anywhere, which causes an exception. That exception kills the map without allowing the other processes to reach their finally blocks.
Also, if you add the line bar = bazz
just after the sleep() call in the try block. Then the first process to reach that line throws an exception (because bazz isn't defined), which causes its own finally block to be run, but then kills the map, causing the other try blocks to disappear without reaching their finally blocks, and the first process not to reach its return statement, either.
What this means for Python multiprocessing is that you can't trust the exception-handling mechanism to clean up resources in all processes if even one of the processes can have an exception. Additional signal handling or managing the resources outside the multiprocessing map call would be necessary.
참고URL : https://stackoverflow.com/questions/49262379/does-finally-always-execute-in-python
'development' 카테고리의 다른 글
boost :: algorithm :: join의 좋은 예 (0) | 2020.07.27 |
---|---|
UML은 실용적입니까? (0) | 2020.07.27 |
Rails에서 이메일을 미리 보려면 어떻게해야합니까? (0) | 2020.07.27 |
Maven Central에서 "치명적 경보 수신 : protocol_version"또는 "피어 인증되지 않음"이 표시되는 이유는 무엇입니까? (0) | 2020.07.27 |
html5에서 투명 캔버스를 만들려면 어떻게해야합니까? (0) | 2020.07.27 |