Python_예외_try: except:

jaam._.mini·2023년 11월 12일
0

📒Python 기초 수학

목록 보기
11/46

예외(exception)란 코드를 실행하는 중에 발생한 에러를 뜻합니다.
오늘은 try: except: 이용한 예외 처리 예제를 풀어보겠습니다!


📌 try: except:


기본 꼴

(1) try에 실행할 코드를 넣고 except에 예외가 발생했을 때 처리하는 코드를 넣습니다.

try:
    실행할 코드
except:
    예외가 발생했을 때 처리하는 코드
else:
	 try 블록 안의 코드가 예외 없이 실행되었을 때 실행
finally:
	 예외 발생 여부와 상관없이 항상 실행
     (보통 파일이나 네트워크 연결 등 리소스를 정리할 때 사용)
try:
    x = int(input("정수를 입력하세요: "))
    result = 10 / x
except ValueError:
    print("정수를 입력해야 합니다.")
except ZeroDivisionError:
    print("0으로 나눌 수 없습니다.")
else:
    print("결과:", result)
finally:
    print("예외처리가 완료되었습니다.")

(2) 이제 숫자를 0으로 나누었을 때 발생하는 예외를 처리해보겠습니다.

try:
    x = int(input('나눌 숫자를 입력하세요: '))
    y = 10 / x
    print(y)
except:    # 예외가 발생했을 때 실행됨
    print('예외가 발생했습니다.')
[결과]
나눌 숫자를 입력하세요: 0 (입력)
예외가 발생했습니다.

특정 예외 처리

(1) except에 예외 이름을 지정해서 특정 예외가 발생했을 때만 처리 코드를 실행하도록 만들어보겠습니다.

def div(n1, n2):
    print('나눗셈 연산')
    try:
        n1 = float(n1)
    except:
        print('첫 번째 피연산자는 숫자가 아닙니다.')
        return

    try:
        n2 = float(n2)
    except:
        print('두 번째 피연산자는 숫자가 아닙니다.')
        return

    if n2 == 0:
        print('0으로 나눌 수 없습니다.')
        return # 멈춤

    print(f'{n1} / {n2} = {n1 / n2}')
    
🏷️만약 2번째 숫자가 0이면 나눗셈을 할 수 없음.
  이런 경우 위와 같이 씀.

(2) 이번에는 ZeroDivisionError를 이용해 만들어 보겠습니다.

def div(n1, n2):
    print('나눗셈 연산')
    try:
        n1 = float(n1)
    except:
        print('첫 번째 피연산자는 숫자가 아닙니다.')
        return

    try:
        n2 = float(n2)
    except:
        print('두 번째 피연산자는 숫자가 아닙니다.')
        return
        
    try:
        print(f'{n1} / {n2} = {n1 / n2}')
    except ZeroDivisionError as e:
        print(e)
        print('0으로 나눌 수 없습니다.')
 
🏷️ZeroDivisionError : 0으로 나눴을때 발생하는 에러

예제(1)

Q> 사용자가 입력한 숫자를 이용해서 산술연산 결과를 출력하는 모듈을 만들되, 예상하는 예외에 대한 예외처리 코드를 작성

[calculator.py]
# 예외 처리 = try, except 이용

def add(n1, n2):
    print('덧셈 연산')
    try: # 숫자로 변경
        n1 = float(n1)
    except: # 숫자가 아니면 예외가 발생하게 만들어 주기!
        print('첫 번째 피연산자는 숫자가 아닙니다.')
        return # 계쏙 실행하면, 에러가 날 것. 따라서 return으로 종료 시켜 줌

    try:
        n2 = float(n2)
    except:
        print('두 번째 피연산자는 숫자가 아닙니다.')
        return

    print(f'{n1} + {n2} = {n1 + n2}') # 마지막에 연산 함수 입력


def sub(n1, n2):
    print('뺄셈 연산')
    try:
        n1 = float(n1)
    except:
        print('첫 번째 피연산자는 숫자가 아닙니다.')
        return

    try:
        n2 = float(n2)
    except:
        print('두 번째 피연산자는 숫자가 아닙니다.')
        return

    print(f'{n1} - {n2} = {n1 - n2}')


def mul(n1, n2):
    print('곱셈 연산')
    try:
        n1 = float(n1)
    except:
        print('첫 번째 피연산자는 숫자가 아닙니다.')
        return

    try:
        n2 = float(n2)
    except:
        print('두 번째 피연산자는 숫자가 아닙니다.')
        return

    print(f'{n1} * {n2} = {n1 * n2}')


def div(n1, n2):
    print('나눗셈 연산')
    try:
        n1 = float(n1)
    except:
        print('첫 번째 피연산자는 숫자가 아닙니다.')
        return

    try:
        n2 = float(n2)
    except:
        print('두 번째 피연산자는 숫자가 아닙니다.')
        return

    # 만약 2번째 숫자가 0이면 나눗셈을 할 수 없음.
    # 이런 경우 아래와 같이 씀.
    if n2 == 0:
        print('0으로 나눌 수 없습니다.')
        return # 멈춤

    print(f'{n1} / {n2} = {n1 / n2}')

# ZeroDivisionError : 0으로 나눴을때 발생하는 에러 CLASS (원래 있는 함수!)
# ▲ if n2 == 0: ~ print(4줄)  대체 가능
#     try:
#         print(f'{n1} / {n2} = {n1 / n2}')
#     except ZeroDivisionError as e:
#         print(e)
#         print('0으로 나눌 수 없습니다.')


def mod(n1, n2):
    print('나머지 연산')
    try:
        n1 = float(n1)
    except:
        print('첫 번째 피연산자는 숫자가 아닙니다.')
        return

    try:
        n2 = float(n2)
    except:
        print('두 번째 피연산자는 숫자가 아닙니다.')
        return

    if n2 == 0:
        print('0으로 나눌 수 없습니다.')
        return

    print(f'{n1} % {n2} = {n1 % n2}')


def flo(n1, n2):
    print('몫 연산')
    try:
        n1 = float(n1)
    except:
        print('첫 번째 피연산자는 숫자가 아닙니다.')
        return

    try:
        n2 = float(n2)
    except:
        print('두 번째 피연산자는 숫자가 아닙니다.')
        return

    if n2 == 0:
        print('0으로 나눌 수 없습니다.')
        return

    print(f'{n1} // {n2} = {int(n1 // n2)}')


def exp(n1, n2):
    print('거듭제곱 연산')
    try:
        n1 = float(n1)
    except:
        print('첫 번째 피연산자는 숫자가 아닙니다.')
        return

    try:
        n2 = float(n2)
    except:
        print('두 번째 피연산자는 숫자가 아닙니다.')
        return

    print(f'{n1} ** {n2} = {n1 ** n2}')
[ex.py]

import calcularot as cc

num1 = input('첫 번째 연산자 : ')
num2 = input('두 번째 연산자 : ')

cc.add(num1, num2)
cc.sub(num1, num2)
cc.mul(num1, num2)
cc.div(num1, num2)
cc.mod(num1, num2)
cc.flo(num1, num2)
cc.exp(num1, num2)

예제(2)

Q> 1부터 1000까지의 소수인 난수 10개를 생성, 소수가 아니면 사용자 예외가 발생

[prime_module.py]

class NotPrimeException(Exception):

    def __init__(self, n):
        super().__init__(f'{n} is not prime number.')

class PrimeException(Exception):

    def __init__(self, n):
        super().__init__(f'{n} is prime number.')

#소수를 구하는 구조
def isPrime(number):
    flag = True
    for n in range(2, number):
        if number % n == 0:
            flag = False
            break

# 소수가 아니면
    if flag == False: 
        raise NotPrimeException(number)
        
# 소수인 경우   
    else: 
        raise PrimeException(number)
import random # 난수 발생
import prime_module as pm # 소수 유무 모듈

primeNumbers = [] # 자료구조 만들어주기

n = 0
while n < 10: #10개가 나올때 까지 반복해야 함

    rn = random.randint(2, 1000)
    if rn not in primeNumbers:
        #중복체크(=리스트에 없다면)

        try:
            pm.isPrime(rn)

        except pm.NotPrimeException as e: # 소수가 아니다
            print(e)
            continue # 필요 없으니까 반복 재실행

        except pm.PrimeException as e: #소수다
            print(e)
            primeNumbers.append(rn) # primeNumbers 리스트에 추가

    else:
        print(f'{rn} is overlap number.') #중복 숫자 발생 시
        continue

    n += 1


print(f'PrimeNumbers: {primeNumbers}')
# 전체적으로 소수값을 나열하는 값

예제(3)

📌* 변수

몇개의 변수가 들어올지 모를때 변수 앞에 사용
def calculate(*gcs):

📌enumerate()

for을 이용한 시퀀스의 인덱스를 반복할때는 enumerate를 사용

for word in enumerate(['A', 'B', 'C'])
	print(word)

(0, 'A')
(1, 'B')
(2, 'C')

⭐global()

예제 중 중요한 부분 톱아보기

globals()함수를 쓰면
g1price, g2price...를 {g}Price로 참조할 수 있음

여기서 {g}g{idx+1}라서 globals()(f'{g}Price')가 하나의 변수로 치환 됨.
(g{idx+1} = g1, g2, g3 ....을 뜻 함)

따라서
totalPrice += globals()[f'{g}price'] * gcsDic[g]
totalPriceg1인 경우 1,200원 * 갯수 로 해석이 가능

Q> 1부터 1000까지의 소수인 난수 10개를 생성, 소수가 아니면 사용자 예외가 발생

[calculatePurchase.py]

# 상품의 가격 설정
g1price = 1200; g2price = 1000; g3price = 800
g4price = 2000; g5price = 900

def formatedNumber(n):
    return format(n, ',')

# ▼사용자가 갯수를 입력하면 총 금액을 출력하는 함수를 만들어야 함
def calculate(*gcs): #변수 : gcs, * :  몇개의 변수가 들어올지 모를때 변수 앞에 사용

    gcsDic = {} # 상품 목록화 딕셔너리 # 정상적인 상품
    againCntInput = {} # 미결제 상품 #비정상적인 상품

    for idx, gc in enumerate(gcs):
        try:
            gcsDic[f'g{idx+1}'] = int(gc) # 상품1번idx+1 = 구매 갯수int(gc)
        except Exception as e:
            againCntInput[f'g{idx+1}'] = gc
            print(e)

    totalPrice = 0
    for g in gcsDic.keys(): #정상적인 상품 계산
        totalPrice += globals()[f'{g}price'] * gcsDic[g]

    print('---------------------------')
    print(f'총 구매 금액: {formatedNumber(totalPrice)}원')
    print('-------- 미결제 항목 --------')
    for g in againCntInput.keys():
        print(f'상품: {g},\t 구매 개수: {againCntInput[g]}')
    print('---------------------------')
[ex.py]

import calculatePurchase as cp

g1Cnt = input('goods1 구매 개수: ')
g2Cnt = input('goods2 구매 개수: ')
g3Cnt = input('goods3 구매 개수: ')
g4Cnt = input('goods4 구매 개수: ')
g5Cnt = input('goods5 구매 개수: ')

cp.calculate(g1Cnt, g2Cnt, g3Cnt, g4Cnt, g5Cnt)

예제(4)

Q> 회원가입 정보 입력 만들기

[mem.py]

#예외 클래스 생성
# 비어있는 정보가 있으면 EmptyDataException 발생
class EmptyDataException(Exception):

    #어떤 값이 비어있는지 알아야 하니까, i 하나 지정
    def __init__(self, i):
        super().__init__(f'{i} is empty!')

def checkInputData(n, m, p, a, ph):

    if n == '':
        raise EmptyDataException('name')
    elif m == '':
        raise EmptyDataException('mail')
    elif p == '':
        raise EmptyDataException('password')
    elif a == '':
        raise EmptyDataException('address')
    elif ph == '':
        raise EmptyDataException('phone')
    else:
        return True

#회원 가입 모듈
class RegisteMember():

    # 정보를 다 받고
    def __init__(self, n, m, p, a, ph):
        self.m_name = n
        self.m_mail = m
        self.m_pw = p
        self.m_addr = a
        self.m_phone = ph
        print('Membership completed!!')

    # 회원정보 출력
    def printMemberInfo(self):
        print(f'm_name: {self.m_name}')
        print(f'm_mail: {self.m_mail}')
        print(f'm_pw: {self.m_pw}')
        print(f'm_addr: {self.m_addr}')
        print(f'm_phone: {self.m_phone}')
[ex.py]

import  mem

m_name = input('이름 입력: ')
m_mail = input('메일 주소 입력: ')
m_pw = input('비밀번호 입력: ')
m_addr = input('주소 입력: ')
m_phone = input('연락처 입력: ')

try:
    mem.checkInputData(m_name, m_mail, m_pw, m_addr, m_phone)
    newMember = mem.RegisteMember(m_name, m_mail, m_pw, m_addr, m_phone)
    newMember.printMemberInfo()

except mem.EmptyDataException as e:
    print(e)

📌in 키워드

값의 존재 여부 검사, 순서 반복

(1) 특정 값의 존재 여부 검사
in 키워드는 어떤 값이 리스트, 튜플, 세트의 요소인지 아닌지 여부를 판단하는 데 사용됩니다.
해당 값이 있으면 True를 없으면 False를 반환합니다.

(2) 반복문에서 순서를 반복
영화 제목이 담긴 리스트가 있고 이 리스트의 요소를 for문을 이용해서 차례대로 출력하고 싶다면 다음과 같이 코드를 작성할 수 있습니다.

movies_of_2019 = ['The Irishman', 'Little Women', 'John Wick: Chapter 3', 'Ford v Ferrari']

for title in movies_of_2019:
  print(title)
  
 """
The Irishman
Little Women
John Wick: Chapter 3
Ford v Ferrari
 """

예제(5)

Q> 은행 입출금, 잔액 프로그램


🏷️__init__메소드라서 중간 중간 새로운 정의 추가가 가능


위 예제를 여러 단계로 나눠 봐야 한다.
(1) 개인통장, (2) 은행 정보, (3) 잔고 부족

(1) 개인 통장에 대한 class 만들기

(2) 은행에 대한 class 만들기

(3) 잔고 부족 class 만들기


(4) 출력을 위한 문구


참고/출처 :
https://dojang.io/mod/page/view.php?id=2398
https://hogni.tistory.com/100
제로베이스 데이터 취업스쿨스터디노트
profile
비전공자의 데이터 공부법

0개의 댓글