왜 파이썬에서 "최종"절이 필요한가?


306

우리가 필요로하는 이유는 확실하지 오전 finallytry...except...finally문. 제 생각에는이 코드 블록

try:
    run_code1()
except TypeError:
    run_code2()
other_code()

이 사용하는 것과 동일합니다 finally:

try:
    run_code1()
except TypeError:
    run_code2()
finally:
    other_code()

뭔가 빠졌습니까?

답변:


422

일찍 돌아 오면 차이가 있습니다.

try:
    run_code1()
except TypeError:
    run_code2()
    return None   # The finally block is run before the method returns
finally:
    other_code()

이것과 비교하십시오 :

try:
    run_code1()
except TypeError:
    run_code2()
    return None   

other_code()  # This doesn't get run if there's an exception.

차이가 발생할 수있는 다른 상황 :

  • except 블록 안에 예외가 발생하는 경우.
  • 예외가 던져 경우 run_code1()만은 아니다 TypeError.
  • continuebreak제어문 과 같은 기타 제어 흐름 문.

1
시도 : #x = Hello + 20 x = 10 + 20 제외 : print '나는 블록을 제외하고 있습니다.'x = 20 + 30 else : print '나는 다른 블록에 있습니다'x + = 1 마지막으로 : '마지막으로 x = % s '% (x)
Abhijit Sahu

89

당신은 사용할 수 finally있는지 파일이나 자원이 닫히거나에 관계없이 예외가 발생하는지의 출시하기 위해 당신이 예외를 catch하지 않는 경우에도 마찬가지입니다. (또는 특정 예외를 잡지 않으면 )

myfile = open("test.txt", "w")

try:
    myfile.write("the Answer is: ")
    myfile.write(42)   # raises TypeError, which will be propagated to caller
finally:
    myfile.close()     # will be executed before TypeError is propagated

이 예에서는 with명령문을 사용하는 것이 더 좋지만 이러한 종류의 구조는 다른 종류의 리소스에 사용될 수 있습니다.

몇 년 후, 나는 독자들이 재미있는 것으로 남용 할 수 있는 블로그 게시물을 썼습니다 finally.


23

그것들은 동등하지 않습니다. 마지막으로 코드는 다른 일이 발생해도 실행됩니다. 정리 코드를 실행하는 데 유용합니다.


15
Finally code is run no matter what else happens무한 루프가 없다면 ... 또는 파워 컷. 또는 os._exit(). 또는 ...
Mark Byers

3
@Mark 실제로 sys.exit는 일반적인 예외를 발생시킵니다. 그러나 예, 프로세스를 즉시 종료시키는 것은 아무것도 실행되지 않음을 의미합니다.
안티 모니

1
@Antimony : 감사합니다. 로 변경되었습니다 os._exit.
Mark Byers

궁금한 점은 예외가 발견 된 경우를 제외하고 코드가 입력되는 경우를 제외하고 정리 코드를 예외 내에 넣을 수없는 이유는 무엇입니까?
Stephen Jacob

2
@Stephen 우선, try 블록에서 돌아 왔을 때도 마지막으로 코드가 실행됩니다. 이 경우 except 절을 누르지 않습니다.
안티몬

18

위의 다른 답변에 추가하기 위해 예외가 발생하지 않은 경우에만 절이 실행 finally되는 반면에 else절은 실행됩니다.

예를 들어, 예외없이 파일에 쓰면 다음이 출력됩니다.

file = open('test.txt', 'w')

try:
    file.write("Testing.")
    print("Writing to file.")
except IOError:
    print("Could not write to file.")
else:
    print("Write successful.")
finally:
    file.close()
    print("File closed.")

산출:

Writing to file.
Write successful.
File closed.

예외가있는 경우 코드는 다음을 출력합니다 (파일을 읽기 전용으로 유지하면 의도적 인 오류가 발생합니다.

file = open('test.txt', 'r')

try:
    file.write("Testing.")
    print("Writing to file.")
except IOError:
    print("Could not write to file.")
else:
    print("Write successful.")
finally:
    file.close()
    print("File closed.")

산출:

Could not write to file.
File closed.

finally예외에 관계없이 절이 실행 되는 것을 볼 수 있습니다 . 도움이 되었기를 바랍니다.


2
OP가 차이를 알고 싶어하기 때문에 질문에 대답하지 않는 "마침내"절을 사용하지 않더라도 작동했을 것입니다. 좋은 예는 IOError와 다른 오류를 일으켜서 finally 절 블록은 예외가 호출자에게 전파되기 전에 실행됩니다.
Reda Drissi

2
나는 else한 가지 몰랐다 . 알아두면 좋습니다.
mazunki

8

코드 블록은 동일하지 않습니다. finally경우 절은 실행됩니다 run_code1()이외의 예외가 발생 TypeError하거나하는 경우는 run_code2()있지만, 예외를 throw other_code()첫 번째 버전에서 이러한 경우에 실행되지 않습니다.


7

첫 번째 예에서 run_code1()그렇지 않은 예외가 발생하면 어떻게됩니까 TypeError? ... other_code()실행되지 않습니다.

finally:버전 과 비교하십시오 : other_code()예외 발생에 관계없이 실행됩니다.


7

에서 설명하고있는 바와 같이 문서finally절을 실행해야합니다 청소 작업을 정의하기위한 것입니다 모든 상황을 .

경우 finally존재, 그것은 '정리'핸들러를 지정합니다. try 절은 어떤을 포함하여, 실행 exceptelse절. 절에서 예외가 발생하여 처리되지 않으면 예외가 일시적으로 저장됩니다. finally절은 실행됩니다. 저장된 예외가있는 경우 finally 조항 끝에서 다시 발생합니다 .

예를 들면 :

>>> def divide(x, y):
...     try:
...         result = x / y
...     except ZeroDivisionError:
...         print("division by zero!")
...     else:
...         print("result is", result)
...     finally:
...         print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'

보시다시피, finally절은 모든 이벤트에서 실행됩니다. TypeError개의 스트링을 분할함으로써 발생은 처리되지 except절과 후 따라서 레이즈 다시 finally절 실행되었다.

실제 응용 프로그램에서 finally 절은 리소스 사용의 성공 여부에 관계없이 외부 리소스 (예 : 파일 또는 네트워크 연결)를 해제하는 데 유용합니다.


4

완벽한 예는 다음과 같습니다.

try:
    #x = Hello + 20
    x = 10 + 20 
except:
    print 'I am in except block'
    x = 20 + 30
else:
    print 'I am in else block'
    x += 1
finally:
    print 'Finally x = %s' %(x)

3

finally"정리 조치" 를 정의하기위한 것 입니다. 이 finally절은 try예외를 처리했는지 여부에 관계없이 명령문을 떠나기 전에 모든 이벤트에서 실행됩니다 .

두 번째 @Byers의 예입니다.


2

마지막으로 주요 작업에 대한 코드를 실행하기 전에 "선택적"코드를 실행하려고 할 때 해당 옵션 코드가 여러 가지 이유로 실패 할 수 있습니다.

다음 예제에서는 어떤 종류의 예외 store_some_debug_info가 발생할 수 있는지 정확하게 알지 못합니다 .

우리는 실행할 수 있습니다 :

try:
  store_some_debug_info()
except Exception:
  pass
do_something_really_important() 

그러나 대부분의 정보 제공자는 너무 모호한 예외를 잡는 것에 대해 불평 할 것입니다. 또한 우리는 단지 pass오류 만을 선택하기 때문에 except블록은 실제로 가치를 추가하지 않습니다.

try:
  store_some_debug_info()
finally:
  do_something_really_important()     

위의 코드는 첫 번째 코드 블록과 동일한 효과를 갖지만 더 간결합니다.


2

몇 년 동안 전문적으로 델파이를 사용하면서 마침내 정리 루틴을 보호하는 법을 배웠습니다. 델파이는 try 블록 이전에 생성 된 모든 리소스를 정리하여 메모리 누수를 유발하지 않도록 최종적으로 사용합니다. 이것은 또한 Java, Python 및 Ruby의 작동 방식입니다.

resource = create_resource
try:
  use resource
finally:
  resource.cleanup

시도와 마지막에 수행 한 작업에 관계없이 리소스가 정리됩니다. 또한 실행이 try블록에 도달하지 않으면 정리되지 않습니다 . (예를 들어 create_resource자체적으로 예외가 발생 함) 코드를 "예외 안전"으로 만듭니다.

실제로 finally 블록이 필요한 이유는 모든 언어가 아닙니다. 예외가 스택을 풀 때 정리를 강제하는 소멸자를 자동으로 호출 한 C ++에서. 나는 이것이 최종 언어와 비교하여 깨끗한 코드 방향으로 한 단계 향상 된 것이라고 생각합니다.

{    
  type object1;
  smart_pointer<type> object1(new type());
} // destructors are automagically called here in LIFO order so no finally required.

2

try 블록에는 하나의 필수 절인 try 문이 있습니다. except, else 및 finally 절은 선택 사항이며 사용자 기본 설정을 기반으로합니다.

finally : Python이 try 문을 떠나기 전에 프로그램을 종료하더라도 모든 조건에서 finally 블록에서 코드를 실행합니다. 예를 들어, except 또는 else 블록에서 코드를 실행하는 동안 Python에서 오류가 발생하면 프로그램을 중지하기 전에 finally 블록이 계속 실행됩니다.


1
이것은 잘못이다. except 서술문은 필수입니다. – Lucas Azevedo 2 월 1 일 12:04 이것은 "except"절없이 try-finally 블록으로 Python 3.5 프로그램을 컴파일하고 실행했기 때문에 잘못되었습니다.
Rob Tow

2
나는 이것을 직접 시도했고 내 불신에 대해서는 예외 조항이 의무적이지 않다.
captainblack

1

다음의 Python3 코드를 실행하여 마지막으로 필요한 것을보십시오.

사례 1 :

count = 0
while True:
    count += 1
    if count > 3:
        break
    else:
        try:
            x = int(input("Enter your lock number here: "))

            if x == 586:
                print("Your lock has unlocked :)")

                break
            else:
                print("Try again!!")

                continue

        except:
            print("Invalid entry!!")
        finally:
            print("Your Attempts: {}".format(count))

CASE2 :

count = 0

while True:
    count += 1
    if count > 3:
        break
    else:
        try:
            x = int(input("Enter your lock number here: "))

            if x == 586:
                print("Your lock has unlocked :)")

                break
            else:
                print("Try again!!")

                continue

        except:
            print("Invalid entry!!")

        print("Your Attempts: {}".format(count))

매번 다음 입력을 시도하십시오.

  1. 임의의 정수
  2. 올바른 코드는 586입니다 (이걸 시도하면 답을 얻을 수 있습니다)
  3. 임의의 문자열

** 파이썬 학습 초기 단계.


1

Excel 시트를 읽으려는 코드를 실행하려고했습니다. say라는 시트가없는 파일이있는 경우 문제가 발생했습니다 : SheetSum 오류 위치로 이동할 수 없습니다! 내가 쓴 코드는 다음과 같습니다.

def read_file(data_file):
    # data_file = '\rr\ex.xlsx'
    sheets = {}
    try:
        print("Reading file: "+data_file)
        sheets['df_1'] = pd.read_excel(open(data_file,'rb'), 'SheetSum')
    except Exception as excpt:
        print("Exception occurred", exc_info=True)
    return sheets

read_file(file)
shutil.move( file, dirpath +'\\processed_files')

오류 제공 :

[WinError 32] 프로세스가 다른 프로세스에서 사용 중이므로 파일에 액세스 할 수 없습니다

나는 전체 try except with finally블록 을 추가 하고 다음과 finally같은 경우에 파일을 닫아야한다고 말합니다 .

def read_file(data_file):
    # data_file = '\rr\ex.xlsx'
    sheets = {}
    try:
        print("Reading file: "+data_file)
        sheets_file = open(data_file,'rb')
        sheets['df_1'] = pd.read_excel(sheets_file, 'SheetSum')
    except Exception as excpt:
        print("Exception occurred", exc_info=True)
    finally:
        sheets_file.close()
    return sheets

read_file(file)
shutil.move( file, dirpath +'\\processed_files')

그렇지 않으면 파일은 여전히 ​​열려 있습니다.

경우 finally존재, 그것은 지정 정리 핸들러를 . try 절은 어떤을 포함하여, 실행 exceptelse절. 절에서 예외가 발생하여 처리되지 않으면 예외가 일시적으로 저장 됩니다. finally절은 실행됩니다. 저장된 예외가있는 경우 finally 조항 끝에서 다시 발생합니다 . 은 if finally절은 또 다른 예외가 발생, 저장된 예외는 새로운 예외의 상황으로 설정됩니다.

..More 여기에

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.