Python Language
예외
수색…
소개
실행 중에 발견 된 오류를 예외라고하며 무조건 치명적이지 않습니다. 대부분의 예외는 프로그램에서 처리하지 않습니다. 선택한 예외를 처리하는 프로그램을 작성할 수 있습니다. 예외 및 예외 로직을 다루는 Python의 특정 기능이 있습니다. 또한 예외에는 풍부한 유형 계층 구조가 있으며, 모두 BaseException
유형을 상속합니다.
통사론
- 예외를 제기하다
- raise # 이미 발생 된 예외를 다시 발생시킵니다.
- 설정 예외 원인 - 원인 # 파이썬 3에서 예외를 발생
- None # Python 3에서 예외 발생 - 모든 예외 상황을 억제
- 시험:
- [예외 유형] [ 식별자로 ] 제외 :
- 그밖에:
- 마침내 :
예외 발생
코드에 조건이 발생하면 잘못된 매개 변수와 같이 처리 방법을 알 수 없으므로 적절한 예외가 발생해야합니다.
def even_the_odds(odds):
if odds % 2 != 1:
raise ValueError("Did not get an odd number")
return odds + 1
예외 잡기
예외를 잡으려면 try...except:
를 사용하십시오. 다음과 같이 예외를 정확하게 지정해야합니다.
try:
x = 5 / 0
except ZeroDivisionError as e:
# `e` is the exception object
print("Got a divide by zero! The exception was:", e)
# handle exceptional case
x = 0
finally:
print "The END"
# it runs no matter what execute.
지정된 예외 클래스 (이 경우 ZeroDivisionError
)는 해당 클래스 또는 예외의 하위 클래스에 해당하는 모든 예외를 포착합니다.
예를 들어 ZeroDivisionError
는 ArithmeticError
의 하위 클래스입니다.
>>> ZeroDivisionError.__bases__
(<class 'ArithmeticError'>,)
따라서 다음과 같이 여전히 ZeroDivisionError
catch합니다.
try:
5 / 0
except ArithmeticError:
print("Got arithmetic error")
마지막으로 정리 코드 실행하기
경우에 따라 일부 예외가 발생했는지 여부에 관계없이 무언가를 정리해야 할 수도 있습니다. 예를 들어 일부 리소스를 정리해야하는 경우가 있습니다.
try
절의 finally
블록은 예외가 발생했는지 여부에 관계없이 발생합니다.
resource = allocate_some_expensive_resource()
try:
do_stuff(resource)
except SomeException as e:
log_error(e)
raise # re-raise the error
finally:
free_expensive_resource(resource)
이 패턴은 ( with
문을 사용하여) 컨텍스트 관리자로 처리하는 것이 더 효과적입니다.
예외 재발생
때로는 로깅 목적으로 검사 할 때 예외를 잡기를 원합니다. 검사가 끝나면 이전처럼 예외가 전파되기를 원합니다.
이 경우 단순히 매개 변수없이 raise
문을 사용하십시오.
try:
5 / 0
except ZeroDivisionError:
print("Got an error")
raise
그래도 호출자 스택에있는 누군가가 예외를 잡아서 어떻게 든 처리 할 수 있다는 것을 명심하십시오. 완성 된 결과물은 어떤 경우에도 발생하기 때문에이 경우 귀찮은 일이 될 수 있습니다 (걸려 넘어 지거나 걸리지 않음). 그러므로 다른 예외 상황을 제기하는 것이 더 좋은 생각 일 수 있습니다. 원래의 예외 상황뿐만 아니라 상황에 대한 의견도 들어 있습니다.
try:
5 / 0
except ZeroDivisionError as e:
raise ZeroDivisionError("Got an error", e)
그러나 이것은 예외 추적을 정확히이 raise
로 줄이는 단점이 있지만 인수가없는 raise
는 원래 예외 추적을 유지합니다.
파이썬 3에서는 raise
- from
구문을 사용하여 원래 스택을 유지할 수 있습니다.
raise ZeroDivisionError("Got an error") from e
레이즈가있는 체인 예외
예외를 처리하는 과정에서 또 다른 예외를 발생시킬 수 있습니다. 예를 들어, 파일에서 읽는 동안 IOError
가 IOError
하면 응용 프로그램 별 오류를 발생시켜 라이브러리 사용자에게 제시 할 수 있습니다.
예외 처리를 처리하는 방법을 보여주기 위해 예외를 연결할 수 있습니다.
>>> try:
5 / 0
except ZeroDivisionError as e:
raise ValueError("Division failed") from e
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
ValueError: Division failed
예외 계층 구조
예외 처리는 예외 클래스의 상속 구조에 의해 결정되는 예외 계층 구조를 기반으로 발생합니다.
예를 들어 IOError
와 OSError
는 모두 EnvironmentError
하위 클래스입니다. IOError
를 포착하는 코드는 OSError
catch하지 않습니다. 그러나 EnvironmentError
를 포착하는 코드는 IOError
및 OSError
모두 잡습니다.
기본 제공 예외의 계층 구조 :
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StandardError
| +-- BufferError
| +-- ArithmeticError
| | +-- FloatingPointError
| | +-- OverflowError
| | +-- ZeroDivisionError
| +-- AssertionError
| +-- AttributeError
| +-- EnvironmentError
| | +-- IOError
| | +-- OSError
| | +-- WindowsError (Windows)
| | +-- VMSError (VMS)
| +-- EOFError
| +-- ImportError
| +-- LookupError
| | +-- IndexError
| | +-- KeyError
| +-- MemoryError
| +-- NameError
| | +-- UnboundLocalError
| +-- ReferenceError
| +-- RuntimeError
| | +-- NotImplementedError
| +-- SyntaxError
| | +-- IndentationError
| | +-- TabError
| +-- SystemError
| +-- TypeError
| +-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning
예외도 객체입니다.
예외는 내장 BaseException
을 상속 한 일반적인 Python 객체입니다. 파이썬 스크립트는 raise
문을 사용하여 실행을 중단함으로써 파이썬이 그 시점에서 호출 스택의 스택 추적과 예외 인스턴스의 표현을 인쇄하도록 할 수 있습니다. 예 :
>>> def failing_function():
... raise ValueError('Example error!')
>>> failing_function()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in failing_function
ValueError: Example error!
'Example error!'
메시지가있는 ValueError
가 'Example error!'
우리의 failing_function()
의해 제기되었는데, 그것은 interpreter에서 실행되었다.
호출 코드는 호출이 발생할 수있는 모든 유형의 예외를 처리하도록 선택할 수 있습니다.
>>> try:
... failing_function()
... except ValueError:
... print('Handled the error')
Handled the error
예외 처리 코드의 except...
부분에 예외 객체를 할당하여 예외 객체를 확보 할 수 있습니다.
>>> try:
... failing_function()
... except ValueError as e:
... print('Caught exception', repr(e))
Caught exception ValueError('Example error!',)
내장 된 파이썬 예외의 전체 목록은 파이썬 문서에서 찾을 수 있습니다 : https://docs.python.org/3.5/library/exceptions.html . 다음은 계층 적으로 배열 된 전체 목록입니다. Exception Hierarchy .
사용자 정의 예외 유형 작성
Exception
에서 상속받은 클래스 만들기 :
class FooException(Exception):
pass
try:
raise FooException("insert description here")
except FooException:
print("A FooException was raised.")
또는 다른 예외 유형 :
class NegativeError(ValueError):
pass
def foo(x):
# function that only accepts positive values of x
if x < 0:
raise NegativeError("Cannot process negative numbers")
... # rest of function body
try:
result = foo(int(input("Enter a positive integer: "))) # raw_input in Python 2.x
except NegativeError:
print("You entered a negative number!")
else:
print("The result was " + str(result))
모든 걸 잡지 마!
모든 Exception
를 잡으려고하는 것은 종종 유혹적이지만 :
try:
very_difficult_function()
except Exception:
# log / try to reconnect / exit gratiously
finally:
print "The END"
# it runs no matter what execute.
또는 모든것 ( BaseException
과 Exception
포함하여 모든 자식 포함) :
try:
even_more_difficult_function()
except:
pass # do whatever needed
대부분의 경우 나쁜 습관입니다. SystemExit
, KeyboardInterrupt
및 MemoryError
와 같이 의도 한 것보다 더 많이 잡을 수 있습니다. 일반적으로 시스템 또는 논리 오류와 다르게 처리해야합니다. 또한 내부 코드가 잘못 수행 할 수있는 부분과 해당 상태에서 올바르게 복구하는 방법에 대한 명확한 이해가 없음을 의미합니다. 모든 오류를 잡는다면 어떤 오류가 발생했는지 또는 오류를 수정하는 방법을 알지 못할 것입니다.
이것은 더 일반적으로 '버그 마스킹'이라고하며이를 피해야합니다. 조용히 실패하거나 악화하는 대신 프로그램을 중단 시키십시오. 더 깊은 실행 수준에서는 실패합니다. (트랜잭션 시스템이라고 상상해보십시오)
일반적으로 이러한 구조는 프로그램의 매우 외부 수준에서 사용되며 버그를 수정하거나 오류를보다 구체적으로 처리 할 수 있도록 오류의 세부 사항을 기록합니다.
여러 예외 잡기
여러 예외 를 잡을 수 있는 몇 가지 방법이 있습니다.
첫 번째는 동일한 방식으로 catch하고 처리하려는 예외 유형의 튜플을 만드는 것입니다. 이 예제는 코드가 KeyError
및 AttributeError
예외를 무시하도록합니다.
try:
d = {}
a = d[1]
b = d.non_existing_field
except (KeyError, AttributeError) as e:
print("A KeyError or an AttributeError exception has been caught.")
다른 예외를 여러 가지 방식으로 처리하려는 경우 각 유형에 대해 별도의 예외 블록을 제공 할 수 있습니다. 이 예제에서 우리는 여전히 KeyError
와 AttributeError
를 잡았지만 다른 방식으로 예외를 처리합니다.
try:
d = {}
a = d[1]
b = d.non_existing_field
except KeyError as e:
print("A KeyError has occurred. Exception message:", e)
except AttributeError as e:
print("An AttributeError has occurred. Exception message:", e)
예외 처리의 실제 예
사용자 입력
사용자가 입력을 통해 숫자를 input
한다고 가정 해보십시오. 입력이 숫자인지 확인하려고합니다. 이것을 위해 try
/ except
를 사용할 수 있습니다 :
while True:
try:
nb = int(input('Enter a number: '))
break
except ValueError:
print('This is not a number, try again.')
참고 : Python 2.x는 대신 raw_input
을 사용할 것입니다. 함수 input
은 Python 2.x에 존재하지만 다른 의미를가집니다. 위의 예에서, input
은 숫자로 평가되는 2 + 2
와 같은 표현식도 허용합니다.
입력을 정수로 변환 할 수 없으면 ValueError
가 발생합니다. 당신은 except
그것을 붙잡을 수 있습니다. 예외가 발생하지 않으면 break
는 루프 밖으로 점프합니다. 루프 다음에 nb
에는 정수가 포함됩니다.
사전
당신이 좋아하는 연속 정수의 목록이 반복되는 상상 range(n)
, 그리고 당신이 사전의 목록이 d
당신은 어떤 특정 정수를 만날 때해야 할 일들에 대한 정보를 포함, 건너 뛰기 말할 d[i]
다음 사람을.
d = [{7: 3}, {25: 9}, {38: 5}]
for i in range(len(d)):
do_stuff(i)
try:
dic = d[i]
i += dic[i]
except KeyError:
i += 1
존재하지 않는 키에 대해 사전에서 값을 가져 오려고하면 KeyError
가 발생합니다.
그밖에
else 블록의 코드는 try
블록의 코드에 의해 예외가 발생하지 않은 경우에만 실행됩니다. 이것은 예외가 발생했을 때 실행하고 싶지 않은 코드가 있지만 해당 코드가 던진 예외를 포착하지 않으려는 경우에 유용합니다.
예 :
try:
data = {1: 'one', 2: 'two'}
print(data[1])
except KeyError as e:
print('key not found')
else:
raise ValueError()
# Output: one
# Output: ValueError
else:
이런 종류는 else:
절을 elif
시작하는 if
와 결합 될 수 없다는 것에주의하십시오. 아래에 들여 쓰기가 필요 if
다음과 같이 else:
:
try:
...
except ...:
...
else:
if ...:
...
elif ...:
...
else:
...