python: 구문 오류 / 예외(런타임 오류)

0

압축 Python

목록 보기
7/11
post-thumbnail

오류

1. 실행 전 오류

  • 구문 오류

2. 실행 후 오류

  • 예외(Exception)
  • 런타임 오류(Runtime Error)

1. 구문 오류(syntax error)

  • 프로그램 실행 전에 발생
  • 문법 오류
  • 프로그램이 시작되지 않는다
print("따옴표를 닫지 않을 테야)
>>
SyntaxError: unterminated string literal (detected at line 1)
또는
SyntaxError: EOL while scanning string literal
  • EOL란 'End Of Line'을 뜻한다

해결

구문 오류의 경우, 수정을 하지 않으면 프로그램 자체가 실행되지 않는다.
따라서 처리를 위해서문법을 준수하여 코드를 제대로 수정해야 한다


2. 예외 / 런타임 오류

  • 프로그램 실행 후 발생
  • 실행 중에 발생
print("프로그램 시작")
print(list_a[1])
>>
프로그램 시작
Traceback (most recent call last):
File "file.py", line 2, in <module>
list_a[1]
NameError: name 'list_a' is not defined

해결

구문 오류와 다르지 않다.


기본 예외 처리

예외를 해결하는 모든 것을 예외처리라 부른다.

해결

  • 조건문을 사용한다
  • try 구문을 사용한다

구문 오류는 프로그램이 실행조차 되지 않았기 때문에 예외 처리 방법으로는 해결할 수 없다.
근본적인 코드를 수정해야 한다.

예외 상황 확인하기

예외가 발생할 상황을 만들어보자.

data = int(input("숫자를 입력하세요\n"))
print(f"입력한 숫자는 {data}입니다")

숫자를 입력하세요
ㅇㅇ
>>
Traceback (most recent call last)
Input In [47], in <cell line: 1>()
ValueError: invalid literal for int() with base 10: 'ㅇㅇ'

숫자를 입력하지 않으면 에러가 뜨게 된다.


해결1: 조건문으로 예외 처리하기

숫자가 아닐 때의 작동을 조건문으로 만들어주는 방법이 있다.

data = input("숫자를 입력하세요\n")

# data가 숫자로만 구성되어 있는지를 검사할 때는 메서드 isdigit()을 사용한다
if data.isdigit():
    data = int(data)
    print(f"입력하신 숫자는 {data}입니다")
else:
    print("숫자를 입력하세요 제발")
>>
숫자를 입력하세요
yes
숫자를 입력하세요 제발
  • .isdigit()STR형 즉, 문자열에 대해 사용하는 메서드이다
    STRING 클래스에 속한 메서드이다.
  • 문자열이 '숫자 리터럴'로 구성되어 있는지를 판별한다
  • True 또는 False를 반환한다

아래와 같이 사용할 수 있다

문자열.isdigit()

#ex
a = if '1234'.isdigit()
print(a)
>>
True

또는

str.isdigit(문자열)

STRING 클래스에 속한 메서드이므로 문자열에 대해서만 사용할 수 있으며, 만약 다른 클래스에 속한 리터럴에 대해 사용하면 런타임 오류를 뱉어낸다.

아래는 .isdigit() 메서드를 정수 리터럴에 사용했을 때의 오류 예이다.

a = 1234
print(a)

if a.isdigit():
    print(a)
>>
1234
Traceback (most recent call last)
Input In [61], in <cell line: 3>()
AttributeError: 'int' object has no attribute 'isdigit'

해결2: try except 구문으로 처리하기

예외가 발생할 상황을 모두 예측하고, 이를 조건문으로 처리하는 것은 굉장히 힘든 일이 되었다. 프로그래밍 언어의 구조적인 문제 때문에, 조건문만을 사용하여 예외처리를 할 수 없는 경우도 생겼다.

이런 경우들 때문에 try except구문이 등장하게 되었다.

구조는 아래와 같다

try:
	예외가 발생할 가능성이 있을 것 같은 코드
    "일단 돌려봐"
except:
	try문에서 예외가 발생했을 때 여기의 코드를 실행한다
    "안 되면 이거 돌리자"

곧장 예를 만들어보자.

try:
	# 여기서 int형을 입력하지 않으면 에러가 뜰 것이다
	number = int(input("숫자 입력합시다\n"))
    print(f"입력한 숫자는 {number}입니다")
except:
	print("숫자 입력하라고요")
>>
숫자 입력합시다
ㅇㅇ
숫자 입력하라고요

이렇게 try except를 사용하여 예외를 피해갈 수 있다.
그런데 try만 사용하여 예외가 발생하는지 여부만 알고 싶지 except에서 별다르게 하고 싶은 게 없다면?
pass를 써준다.

try:
	"이거 일단 해보고"
except:
	pass
    # 아무 것도 하지 않겠다

이걸 잘 활용하면 머리를 덜 쓰고(?) 기능을 구현할 수 있다.
'숫자로 변환되는 것들만 리스트에 넣기'라는 기능을 구현한다고 치겠다.

  1. for문 안에서 차례차례 if문을 통해 숫자인지 판별한다
  2. 조건에 부합하는 애들은 append()처리한다
numbers = ["1", "2", "3", "4", "spy", "5"]

list_numbers = []

for item in numbers:
    
    try:
        float(item)
        list_numbers.append(item)
    except:
        pass

print(list_numbers)
>>
['1', '2', '3', '4', '5']
  • 문자열 "spy"를 훌륭하게 배척한 결과를 볼 수 있다
    if문에서 조건을 생각하지 않아도 된다(개꿀)

try except구문은 if에 비해 아주 야아악간 느리다.
하지만 속도가 그리 중요하지 않으며 좀 더 쉽게 작성하는 것을 원한다면 try except구문을 채용한다. (테스트라든지)

그런데 여기서 끝나는 게 아니라, try exceptelse를 추가로 붙일 수 있다.

구조는 아래와 같다.

try:
	일단 해보자
except:
	예외가 발생하면 이걸 하자
else: 
	어 근데 try가 되네?
    그럼 tryelse까지 실행하자

위에서 썼던 코드를 try except else구조로 써보겠다.

try:
    number = int(input("숫자를 입력하세요\n"))
except:
    print("숫자 입력하라고요")
else:
	print(f"입력하신 숫자는 {number}입니다")

>>
숫자를 입력하세요
5
입력하신 숫자는 5입니다

이런 식으로 사용할 수도 있다.

그런데 여기에 또 하나 더 붙일 수 있다.
finally를 추가하는 것이다.

finally구문은 예외가 발생하든 말든 무조건 실행한다.
위치는 else구문과 동일한 위치이다.

단, elsefinally를 함께 사용한다면 else 뒤에 위치해야 한다.
try 뒤에 except 대신 finally를 사용할 수 있다.

정리해보면
try + except
try + except + else
try + except + else + finally
try + finally
위와 같은 조합이 나온다

finallyfile 처리에서의 close여부와 자주 엮인다고 한다.
하지만 이는 크게 관련 없으며, 오히려 file 처리에서는 file 객체closed 속성으로 알 수 있다.

try:
	file = open("info.txt", "w")
    file.close()
except Exception as e:
	print(e)

print("file.closed?:", file.closed)
>>
file.closed?: True

이런 식이다.
물론, try except 구문이 다 끝나고 나서 별개로 file.close()를 넣어줘도 깔끔하다.

요는 file.close()를 수행할 때, 반드시 finally를 써야 한다는 것은 말도 안 된다는 것이다.

반복문과 함께 사용하여 finally가 반드시 실행되는 꼴을 한번 보도록 하겠다.
break를 사용해도 finally는 반드시 실행하고 반복문을 빠져나간다.

print("프로그램이 시작되었습니다")

while True:
	try:
    	print("try 구문이 실행되었습니다")
        # 여기서 반복문을 빠져나가야 하지만
        break
        print("try 구문의 break 뒤입니다")
    except:
    	print("except 구문이 실행되었습니다")
    finally:
    	print("finally 구문은 아무튼 실행됩니다")
    print("while 구문의 마지막 위치입니다")

print("while구문 밖입니다\n프로그램이 종료됩니다")
>>
프로그램이 시작되었습니다
try 구문이 실행되었습니다
finally 구문은 아무튼 실행됩니다	# 아무튼 실행된 것을 볼 수 있다
while구문 밖입니다				# 이후에는 반복문을 빠져나간다
프로그램이 종료됩니다

정리

  • .isdigit()은 문자열이 숫자 리터럴로 이루어졌는지를 판별한다
  • .isnumeric()isdigit()보다 보다 폭 넓게 숫자로 인정한다
    그림처럼 생긴 놈도 숫자로 볼 수 있으면 True를 반환한다
  • .isdecimal()은 가장 까다롭다
    입력키의 0~9까지로만 이루어진 숫자만 True를 반환한다
    따라서 제곱 표현(표준 키보드로 곧장 입력할 수 없음)마저 False를 반환한다

예외처리

  • try except는 매우 유용하다
  • finallybreak가 있어도 실행된다

0개의 댓글