본문 바로가기

IT

18. 파이썬 - 예외처리 , 파일 입출력(w,a,r모드)

예외처리 

 

에러에는 2가지 종류가 있다.

Error : 우리 프로그램의 문제가 아닌 운영체제등 외부의 문제 ex) 운영체제 다운, 컴퓨터 사향 낮음 프로그램이 안돌아감

Exception : 코딩이 잘못된 경우.   ex) 버그, 프로그램 팅김.

우리는 exception에 대해서 예외 처리를 해야한다.

try:
    예외  발생 가능성이 있는 코드
    int(input( ))

except:
    예외 발생시 실행할 코드
    print('숫자만~')
finally:
   무조건 실행할 코드
   예외 x  예외 O
try O X
  X O
  O O

 

예외처리 - try ~ except

'''

* 예외처리
-프로그램은 실행중에 사용자와 끊임없는 상호작용을 한다.
-그러나 프로그램 사용자는 예측불가의 행동을 할 수 있으며 잘못된
 사용으로 인해 에러를 발생시킬 수 있다.
 -프로그램에서 예외가 발생하면 프로그램이 비정상 종료되기 때문에
  예외처리 문법을 통해 프로그램이 정상 작동할 수 있도록 코드를 구성해야한다.
 
 -예외처리 키워드는 try~ except를 사용해야한다.
 -try블록 내부에는 예외 발생 가능성이 있는 코드를 작성한다.
 -exception에는 try에서 예외가 발생할 시 처리할 코드를 작성한다.
 -try내부에서 예외가 발생한다면 즉시 try의 실행을 중단하고
  except의 코드를 실행한다.

'''

n1 = 10
n2 = 0
#result = n1 / n2
#print("%d / %d = %d" % (n1, n2, result)) 
# 현재 바로 위에있는 문구는 에러를 발생할수 있는 코드이다. 만약 n2에 0이들어가면
# result = n1 / n2
#ZeroDivisionError: division by zero 라는 에러문구가 발생된다 때문에 아래처럼 작성해야한다.

try:
    result = n1 / n2
    print("%d / %d = %d" % (n1, n2, result))
except:
    print("0으로 나눌 수 없습니다.")

print("프로그램 정상 종료!")

 

다중 예외처리 

'''
* 다중 예외처리
-한 개의 try블록에서 발생하는 예외의 원인에 따라 다르게 예외처리를 하는 방법.
- 자주 발생하는 예외
1.NameError: 정의되지 않은변수, 함수, 클래스를 사용할때 발생. # -- is not defined
2.ValueError: 주로 형 변환 시 내부 값의 형식이 잘못되었을때  # invalid literal
3.ZeroDivisionError: 숫자를 0으로 나눌 경우 발생.
4.IndexError: 문자열이나 리스트 등 시퀀스 데이터의 존재하지 않는 인덱스를 참조했을 경우 발생
5.TypeError: 연산 수행시 데이터의 타입이 일치하지 않을 경우 발생.

- 이렇게 5가지 말고도 다른 에러들도 많다. 파이썬 라이브러리에서 찾아보면된다.
- ** 또한, 다중 예외처리말고 미쳐 생각지도 못한 에러들은 어떻게 처리할것인지도 알아야한다.
     이건 맨마지막 except에 적어줘야한다. 왜냐면 except는 순서대로 실행되므로
'''

#NameError
#print(apple)  #NameError: name 'apple' is not defined
#insert()
#stu = Student()

#ValueError
#int("3.14") #ValueError: invalid literal for int() with base 10: '3.14'

#IndexError
#s = "hello"
#print(s[6]) #IndexError: string index out of range

#TypeError
#print(10 ** "hello")

print("-" * 40)
s = input('정수: ')

try:
    point = int(s) # ValueError 가능성
    print(150 / point) # Zero~ 가능성
except ValueError:
    print("숫자로만 입력하세요.")
except ZeroDivisionError:
    print("0으로 나눌 수 없습니다.")
except:
    print("알 수 없는 오류 발생! 점검 후 조치하세요.")

print("프로그램 정상 종료!")

 

예외 상황과 상관없이 꼭 실행시켜줘야하는 코드들이있다. :  finally

순간 강제로 예외를 발생시킬때 사용 (이렇게 하면안된다를 강조하고 싶을때) : raise

'''

*finally
-finally는 예외 발생 여부와 관계없이 항상 실행해야하는 코드를 작성하는 예외처리의 키워드이다.

'''

pets = ['거북이', '타란튤라', '전갈']

for i in range(4) :
    try:
        print(pets[i], "키울래용!")
    except:
        print("애완동물의 정보가 없습니다.")
    finally:
        print("애완동물 넘좋아~~")
        
print("프로그램 정상 종료")


'''
*raise
-프로그램 내부에서 raise를 만나는 순간 강제로 예외가 발생하게 된다.
-보통 함수를 호출할때 예외처리 구문 try~except를 강요하고 싶을 때  사용하는 키워드이다.

'''

print("-" * 40)
def withdraw(money):
    if money > balance:
        raise ValueError # balance보다 money가 더 크면 파이썬에서는 걍 마이너스 값을 출력한다.
    return balance - money # 하지만 예외처리로 하여 잔액이 부족합니다라고 출력가능하다.
# 그치만 조금더 강하게 더큰값을 넣으면 안된다는걸 알려주고싶을때 사용하는게 raise이다.

balance = 5000

try:
    result = withdraw(30000)
    print("출금 후 잔액: %d원" % result)
except:
    print("잔액이 부족합니다.")


---------------------------------결과--------------------------------
거북이 키울래용!
애완동물 넘좋아~~
타란튤라 키울래용!
애완동물 넘좋아~~
전갈 키울래용!
애완동물 넘좋아~~
애완동물의 정보가 없습니다.
애완동물 넘좋아~~
프로그램 정상 종료
----------------------------------------
잔액이 부족합니다.

 

파일 입출력 _ w, a모드

'''
램은 휘발성이다. 그래서 파일을 빼내면 다 날라간다.

* 파일입출력
- 프로그램이 생성한 정보를 좀 더 오래 저장할 때는 파일에 기록합니다.
- 메모리는 속도는 빠르지만 전원이 끊어지면 정보를 잃어버리기 때문에 하드디스크에 저장해야 데이터를 오래 보관할 수 있다.
- 파일은 정보를 저장하는 기본단위이며 문서나, 이미지, 멀티미디어 자료도 모두 파일 형태로 보관할수 있다.
-파이썬에서 파일 입출력을 할 때는 open()이라는 함수를 사용합니다.
 ex) open(파일경로, 모드)
- 파일 경로는 입출력 대상의 파일경로입니다.
-모드는 읽기, 쓰기, 추가 등 무엇을 할지를 결정하는 인수입니다.

- 모드의 종류
1. r: 파일을 읽어들입니다. 읽어들일 파일이 없으면 예외가 발생합니다. (예외처리해야한다.)
2. w: 파일에 데이터를 저장합니다. 파일이 이미존재하면 덮어씁니다. 
3. a: 파일에 데이터를 추가합니다. (w, a의 차이는 덮어씌우느냐, 아래에 더 추가하느냐)
 
 '''

 
# 파일 저장 기능 (write)
file_path = r"D:\수빈\py1530\ringdingdong.txt"

data = """링딩동링딩동동동리리링딩동~~~~
링링링딩딩동  """ 
           
try:
    #파일 입출력을 할 때는 내장함수 open()을 사용합니다.
    #첫번째 인수로 파일 경로를, 두번째 인수로 모드를 설정.
    f = open(file_path, "w") #파일을 만들어서 열고 w모드로 쓰인다.
    # 만약 a모드를 쓰고싶으면 여기 코드에서 바끼는건 30번 코드에 w를 a로 고쳐주면된다.
    #파일을 저장할 때는 파일 객체가 제공하는 write()메서드를 사용하여 
    #저장할 데이터를 인수로 전달합니다.
    f.write(data) #데이터 쓰기
    print("파일 저장이 완료되었습니다.")
except:
    print("지정한 경로가 올바르지 않습니다.")
finally:
    #파일 입출력은 하드디스크에 접근하는 코드이므로
    #반드시 메모리 자원을 반납하는 코드를 적어야한다.
    f.close() # 파일을 닫아주기

 

퀴즈

'''
사용자의 입력을 파일(xxx.txt)에 저장하는 프로그램을 작성하라.
(단, 프로그램을 다시 실행하더라도 파일명이 동일하다면 
기존 작성한 내용을 유지하고 새로 입력한 내용이 추가되어야 한다.
또한, 파일명도 입력받아 저장)

다음은 실행 예제이다.
출력예시: "저장할 내용을 입력: "

실행 할 때마다 사용자가 입력한 내용이 xxx.txt 파일에 추가되어야한다.

'''

f_name = input("파일명을 입력:")
user_input = input("저장할 내용을 입력: ")
f_path = "D:/PY1530/%s.txt" % f_name

try:
    f = open(f_path, "a") #내용추가를 위해 a사용
    f.write(user_input + "\n") #입력된 내용을 출단위로 구분하기 위해 줄바꿈 문자
    print("파일저장성공!")
except:
    pass
finally:
    f.close

 

파일 읽기 기능(read)

'''
*파일 읽기 기능(read)

-파일에서 데이터를 읽어올 때는 분량에 따라 적당한 메서드를 사용합니다.

1.read() : 파일 전체 데이터를 한번에 읽어서 리턴
2. readline(): 파일 데이터를 한줄씩 읽어서 리턴 (1.번의 과부화 막음)
3. readlines(): 파일 전체를 읽어 한줄씩 분리하여 리스트에 담아서 리턴

'''

file_path =  r"D:\수빈\py1530\ringdingdong.txt"

try:
    f = open(file_path, "r")
    text = f.read()
    print(text)
except:
    pass
finally:
    f.close()
    
'''
-read()메서드는 파일을 한번에 읽을 수 있어 편리하지만
 파일 용량이 크면 메모리 소모가 심해지는 단점이 있다.
 - 따라서 큰 파일을 읽을 떄는 read()의 인수로 읽을 양을 지정하여 조금씩
  반복하여 읽어들이는 것이 좋다. 

'''

print("-" * 40)

try:
    f = open(file_path, "r")
    while True:
        text = f.read(10)
        if len(text) == 0 : break
        print(text, end="") #end=""는 파일안 텍스트도 줄바꿈시 \n가 내장되어 있고 이것도 1문자로 치기 때문
    print(text, end = "")
except:
    pass
finally:
    f.close()
    
    
'''
-readline()은 데이터를 자동으로 \n을 기준으로 
 한 줄씩 읽어들이기 때문에 텍스트를 줄 단위로 관리하기 좋다.
'''

print("-" * 40)
try:
    f = open(file_path, "r")
    text = f.readline()
    print(text) # 첫번째 딱 한줄만 출력한다.
except:
    pass
finally:
    f.close()
# readline역시 반복문으로 처리할 수 있다.

print("-" * 40)

try:
    f = open(file_path, "r")
    while True:
        text = f.readline()
        if not text : break
        print(text, end="")  # while반복문으로 한줄씩 계속 출력한다.
except:
    pass
finally:
    f.close()
    
    
'''
readlines()는 파일 데이터를 한줄씩 문자열로 만들어 리스트 형태로
리턴하기 떄문에 데이터를 리스트의 인덱싱이나 for문으로 관리하기 좋다.

'''
print("-" * 40)
try:
    f = open(file_path, "r")
    rows = f.readlines()
    print(rows)
except:
    pass
finally:
    f.close()
    
    ----------------------결과----------------------------------
    
    링딩동링딩동동동리리링딩동~~~~
링링링딩딩동  
----------------------------------------
링딩동링딩동동동리리링딩동~~~~
링링링딩딩동  ----------------------------------------
링딩동링딩동동동리리링딩동~~~~

----------------------------------------
링딩동링딩동동동리리링딩동~~~~
링링링딩딩동  ----------------------------------------
['링딩동링딩동동동리리링딩동~~~~\n', '링링링딩딩동  ']