20210109_ Python 입문7, txt파일 읽기 쓰기, 에러 예외 처리

6 분 소요

Python 입문 07


Python 파일 읽기와 쓰기

  Python에서 파일을 읽고, 쓰려면 기본적으로 open 함수와 with 문을 알아야 한다.


1. open 함수와 with

  • open함수를 통해 파일 객체를 생성해야 한다.
파일 객체 = open('./경로.파일이름', '파일 열기 모드')
  • 파일 열기 모드 : r(읽기모드) , w(쓰기모드), a(추가모드) <- read , write, append 의 앞글자

  • 그리고 파일객체.close()로 항상 파일 객체를 닫아주어야 한다. -> 안그러면 계속 파일이 열려있는 상태이고 다시 파일에 어떤 기능을 수행할때 부딪혀 에러가 난다.

  • 위 close 때문에 with을 통하면 with문이 끝나면 자동으로 닫힌다.


2. 파일 읽기

1) 접근법

f = open('./resource/review.txt', 'r') # 1. open함수를 사용하여 파일 객체를 지정해 본다.
print(type(f)      # 2. f 파일 객체가 어떤 타입인지 확인해 본다.
print(dir(f))      # 3. f 파일 객체가 어떤 함수(속성)를 가지고 있는지 본다.
                   # 4. read 함수가 있는 걸 확인했다.
content = f.read() # 5. read함수를 f에 사용하여 content에 반환해 본다.
print(content)     # 6. 값을 확인해 본다. 
f.close()          # 7. 사용한 파일을 닫아준다.


2) with,alias와 list 형 변환 활용 (iter 함수)

with open('./resource/review.txt','r') as f:
# 1. with문을 시작하고 open함수 사용하고 f로 alias 를 주었는데 위에서 한 파일객체 지정을 빠르게 준거라고 볼 수 있다.
    c = f.read() # 2. c에 파일 값을 반환해 본다.
    print(list(c)) # 3. list형으로 바꾸어 출력한다. list 사용시 for 문 사용 가능하다. 이때는 한 라인씩 리스트가 아니라 한 글자씩 리스트를 만듦
    print(iter(c)) # 3-1. iter 함수를 사용해 iterable 하게 만들어도 for 문이 가능하다. 이때는 1 line 씩 가져옴


3) 파일 읽기 for문 활용 (strip 함수)

with open('./resource/review.txt', 'r') as f: 
    for c in f: # 1. 파일 객체 f가 iterable 하기 때문에 바로 for 문에 사용
        print(c) # 2. 1 line(줄)씩 결과문이 나옴
# 3.  python은 print시 한줄이 끝나면 자동으로 엔터를 치는데 
# 기존에 파일을 작성하면서 친 엔터를 '/n'으로 받아 들여 먼저 엔터 치고 또 print시 엔터를 치게 되는 것  
        print(c.strip()) 
# 4. strip함수 사용하면 괄호안에 있는 문자(공백 포함)를 양쪽에 제거한다. 


4) read , readline , readlines

  • read 사용 (개행 포함)

   파일 전체의 내용을 하나의 문자열로 읽어온다.

with open('./resource/review.txt', 'r') as f: 
    content = f.read() # 1. 파일 전체를 읽어옴
    print(">", content) # 2. 전체를 읽어온걸 출력
    print(">", content) # 3. 전체를 읽어온걸 출력
    
    content = f.read() # 4. 근데 아직 파일이 꺼지지 않은 상태에서 이미 파일을 다 읽었는데 더읽을 수가 없음
    print(">", content) # 5. 내용 없음 출력


  • readline 사용 (개행 포함)

   한번에 하나의 라인을 읽어옴

with open('./resource/review.txt', 'r') as f: 
    line = f.readline() # 1. 한줄 읽고 현재 커서는 한줄 끝에 있음 
    while line:
        print(line, end='#### ') # 2. 개행 포함해서 가져오기 때문에 print시 개행을 '#### '으로 바꾸었음 그리고 1줄 출력
        line = f.readline() # 3. 다시 다음줄 읽어 오기


  • readlines 사용 (개행 포함)

   파일 전체를 한라인씩 읽어와서 리스트를 만들어줌

with open('./resource/review.txt', 'r' as f:
    content = f.readlines()
# 1. 개행 문자까지 포함한 한줄을 원소로 하는 파일 전체 list를 형성
    for c in content:
        print(c, end='') # 2. 원소 print시 개행을 '' 없애서 공백 줄 형태를 없앰


5) txt 파일 숫자 평균 구하기

score = [] # 1. 숫자 담을 score list 생성
with open('./resource/score.txt', 'r') as f:
    for c in f: # 2. f 파일에서 하나씩 가져와
        score.append(int(c))
    # 3. score list 에 가져온 c 를 숫자로 변환해서 넣어라
    print(score) # 4. score list 확인

print('Average : {0:3.2f}'.format(sum(score)/len(score)))
# 5. 출력해라 'Average : {0인덱스:3자리.소수점2자리 실수로}'.format(합/개수) # len 원소 숫자 세는 함수임


3. 파일 쓰기

  • 새로운 파일을 설정하고 open 하면 새롭게 만들어지고 내용이 들어가고, 기존 파일설정하고 내용 쓰면 덮어쓰기로 기존꺼는 삭제됨


  • 기본적으로 모드 w 변경, 함수만 write로 쓰면 똑같고 다만 내용 넣을 때 개행 \n을 내용 끝에 넣어줘야함 그래야 파일에서 줄바꿈이 됨


1) write , append

  • write
with open('./resource/text1.txt', 'w') as f: # 없는 파일도 경로 지정하고 write 모드로 변경
    f.write('Niceman!\n') # 개행 조심, 파일 생겼고 Niceman!이 쓰여져 있음


  • write 활용 (로또 번호 생성)
'로또 번호 생성'
from random import randint # 1. bulitins 패키지 중 하나 random에서 randint 함수를 가져온다
with open('./resource/text2.txt', 'w') as f:
    for cnt in range(6): 
    # 2. range 0~5까지 반복 
        f.write(str(randint(1, 46))) 
        # 3. f 파일에 쓴다. randint 랜덤한 정수(1에서, 45까지)를 str 문자로 변환해서
        f.write('\n') # 4. 개행 쓴다.


  • writelines를 통한 리스트 저장
with open('./resource/text3.txt', 'w') as f:
    list = ['kim\n','park\n','cho\n']
    f.writelines(list)


  • 쓰기 모드에서 결과값 파일에 저장(콘솔X)
with open('./resource/test4.txt', 'w') as f:
    print('test_message1!', file=f) # 결과값이 콜솔로 찍히지 않고 f파일로 들어가서 쓰여짐 
    print('test_message2!', file=f)


  • append(덮어쓰기X , 내용 추가)
with open('./resource/text1.txt', 'a') as f: # 해당 파일 경로 지정하고 append 모드로 변경
    f.write('Goodman!\n') # 아까 그 파일내 niceman! 바로 뒤에 붙여짐(\n 없으면) \n 이 있으면 줄바꿈으로 지정됨






Python 예외처리

  코드를 만들면서 에러가 발생하지 않을 순 없다. 그렇기 때문에 에러가 발생했을 때 어떻게 표시를 보이게 할 것인가 이다.

  보통 에러는 문법적 에러, 코드 실행(런타임)에러가 발생하는 데 주로 런타임 에러가 중요하다. 이렇게 에러들을 linter라고 코드 스타일, 문법체크 하게 도와주는 것이 있다. python linter에서 내보내는 메세지를 알아보자

1. Error messages

1) SuntaxError : 잘못된 문법

  • 보통 ',: 누락 또는 존재하지 않는 문법을 사용한 경우 발생

2) NameError : 참조 변수 없음

  • 존재하지 않는 변수를 사용한 경우

3) IndexError : 인덱스 범위 오버

  • 존재하지 않는 인덱스를 사용하는 경우

4) KeyError : 키 에러

  • 존재하지 않는 키를 사용한 경우 (get메서드를 통해서 에러 발생을 막을수 있음 결과가 none이라고 발생)

5) AttributeError : 모듈, 클래스에 있는 잘못된 속성 사용시

  • 존재하지 않는 속성,함수, 클래스를 사용한 경우

6) ValueError : 참조 값이 없을 때

  • 존재하지 않는 값을 불러 올때

7) TypeError

  • 맞지 않는 타입 끼리 사용한 경우( + 사용시)

8) ZeroDivisionError

  • 0 나누기 에러

9) FileNotFoundError

  • 경로에 파일이 없는 경우


2. 예외 처리 구조

  • try : 에러가 발생할 가능성이 있는 코드
  • excet : 에러가 났을 때 하고자 하는 코드
  • else : 에러가 발생하지 않은 경우 코드
  • finally : 항상 실행 하고자 하는 코드

1) 어떤 에러가 날지 예상 가능한 경우

name = ['kim', 'lee', 'park']

try: # 1. 에러가 날 가능성이 있는 코드 작성(검사하고자 하는)
    z = 'kim' # z 가 kim 이면
    x = name.index(z) # x 에 kim 인덱스 리턴
    print('{} found it! {}in name'.format(z, x+1)) # kim foun it! 1 in name
except ValueError: # 2. z 가 kang 이면 ValueError 발생할 거니까 
    print('Not found it! - Occurred ValueError!') # 이때는 이렇게 실행
else:               # 3. try 문이 정상적으로 실행됬을때 나타남
    print('Ok! else!') 


2) 어떤 에러가 날지 모르는 경우

try:
    z = 'jin'
    x = name.index(z)
    print('{} found it! {}in name'.format(z, x+1)) 
except: # 그냥 except 처리 
    print('Not found it! - Occurred Error!')
else:
    print('Ok! else!')
finally: # 예외가 발생하든 아니든 무조건 출력
    print('finally ok!') #  보통 리소스 닫을때 f.close


3) 예외 처리 없이 그냥 접근하면 출력하는 코드

try:
    print('Try')
finally:
    print('ok finally!!')    # 코드 실행만 하면 출력 되므로 누군가가 접근하면 무조건 실행 되는 코드 임


4) 여러가지 에러에 대한 예외 처리 하여 필터링 식 코드

  • 순서 주의 해야함(Exception이 마지막에 와서 다 잡을 수 있도록 해야함)

  • except에 alias 사용도 가능

try:
    z = 'jin'
    x = name.index(z)
    print('{} found it! {}in name'.format(z, x+1)) 
except ValueError:                                 # 예외를 여러개 잡을 수 있음
    print('Not found it! - Occurred Error!')
except IndexError: #  as l 로 alias 잡고 print(l)로 설정하면 IndexError 그대로 표시함
    print('Not found it! - Occurred Error!')
except Exception:                                   # Exception 이 제일 위에 있으면 모두 잡기 때문에 뭔지 모르고 그후에 설정한 에러잡는 기능이 있으나 마나임
    print('Not found it! - Occurred Error!')        # 순서가 중요함 그래서 최종적으로 Exception을 준다.
else: 
    print('Ok! else!') 
finally: 
    print('finally ok!')


5) raise를 이용한 에러 직접 발생

try:
    a = '369'
    if a == 'kim':
        print("ok 허가!")
    else:
        raise ValueError # kim 씨가 아닌사람이 접근했을 때 ValueError를 일으켜서 알려주는 거지
except ValueError:
    print('문제발생!')
except Exception as f:
    print(f)
else:
    print('ok!')