Development Tip

Python 강좌 12 - File & Exception

MoonLight314 2024. 12. 23. 11:09
728x90

안녕하세요, MoonLight입니다.

이번 Post에서는 Python의 파일 입출력과 예외처리에 대해서 알아보도록 하겠습니다.

 

 

1. 기본 사항

 

 

 

1.1. 파일 입출력

Python의 파일 입출력(I/O)은 파일을 읽고 쓰는 작업을 처리하기 위한 강력하고 간단한 방법을 제공합니다. 아래에서 파일 입출력의 전반적인 개념, 다양한 파일 모드, 파일 작업의 주요 메서드, 그리고 예제를 자세히 설명합니다.

1.1.1. 파일 열기 (open() 메서드)

Python에서 파일 작업을 시작하려면 open() 함수를 사용합니다. 이 함수는 파일을 열고 파일 객체를 반환합니다.

기본 구문

file = open('filename', mode)

filename : 파일 이름 (경로 포함 가능).

mode : 파일 열기 모드(아래 참조).

파일 모드

모드 의미
읽기/쓰기
파일이 없을 때
'r'
읽기 전용
읽기 오류 발생
'w'
쓰기 전용
(기존 내용 삭제) 쓰기 새 파일 생성
'x'
새 파일 생성
(이미 존재하면 오류) 쓰기 새 파일 생성
'a'
쓰기
(기존 내용 뒤에 추가) 쓰기 새 파일 생성
'b'
이진 모드 읽기/쓰기
-
't'
텍스트 모드 (기본값) 읽기/쓰기
-
'+'
읽기와 쓰기 읽기/쓰기
-

1.1.2. 파일 닫기

파일 작업을 완료한 후에는 파일을 닫아야 합니다. 이는 메모리를 해제하고 데이터 손상을 방지합니다.

file.close()

팁 : 파일을 열 때는 항상 with 문을 사용하는 것이 좋습니다. with 블록이 끝나면 파일이 자동으로 닫힙니다.

with open('example.txt', 'r') as file:
    data = file.read()
# 파일이 자동으로 닫힘

1.1.3. 파일 읽기

메서드 요약

file.read(size) : 파일 내용을 문자열로 읽습니다. size를 지정하면 해당 크기만큼 읽습니다.

file.readline() : 한 줄씩 읽습니다.

file.readlines() : 파일의 모든 줄을 읽고 리스트로 반환합니다.

예제

# 파일 전체 읽기
with open('example.txt', 'r') as file:
    content = file.read()
    print(content)
# 파일을 줄 단위로 읽기
with open('example.txt', 'r') as file:
    for line in file:
        print(line.strip()) # 줄바꿈 제거

출력 예시 (파일 내용이 "Hello\nWorld"라면):
Hello
World

1.1.4. 파일 쓰기

메서드 요약

file.write(string) : 문자열을 파일에 씁니다.

file.writelines(list) : 문자열 리스트를 파일에 씁니다.

예제

# 새 파일에 쓰기
with open('output.txt', 'w') as file:
    file.write("Hello, World!\n")
    file.write("This is a new line.")

# 리스트를 파일에 쓰기
lines = ["Line 1\n", "Line 2\n", "Line 3\n"]
with open('output.txt', 'a') as file: # 추가 모드
    file.writelines(lines)

출력(output.txt):
Hello, World!
This is a new line.Line 1
Line 2
Line 3

 

 

 

1.1.5. 이진 파일 읽기 및 쓰기

텍스트 파일이 아닌 이미지, 동영상, PDF와 같은 이진 파일을 처리할 때는 b 모드를 사용합니다.

예제

# 새 파일에 쓰기
with open('output.txt', 'w') as file:
    file.write("Hello, World!\n")
    file.write("This is a new line.")
# 리스트를 파일에 쓰기
lines = ["Line 1\n", "Line 2\n", "Line 3\n"]
with open('output.txt', 'a') as file: # 추가 모드
    file.writelines(lines)

출력(output.txt):
Hello, World!
This is a new line.Line 1
Line 2
Line 3

 

 

 

1.1.6. 파일 작업 중 오류 방지

파일이 존재하지 않을 수 있으므로 오류 처리를 위해 try-except를 사용할 수 있습니다.

try:
    with open('nonexistent.txt', 'r') as file:
        content = file.read()
except FileNotFoundError:
    print("File not found.")

1.1.7. 파일 작업 고급 기능

파일 위치 이동 (seek와 tell)

file.seek(offset, whence) : 파일 포인터 위치를 이동.

offset : 이동할 바이트 수.

whence : 기준 (0=파일 시작, 1=현재 위치, 2=파일 끝).

file.tell() : 현재 파일 포인터 위치 반환.

with open('example.txt', 'r') as file:
    file.seek(5) # 5번째 바이트로 이동
    print(file.read()) # 이후부터 읽기

JSON 파일 읽기 및 쓰기

Python에서는 json 모듈을 사용하여 JSON 형식 파일을 쉽게 처리할 수 있습니다.

예제

import json

# JSON 쓰기
data = {'name': 'Alice', 'age': 30, 'is_student': False}
with open('data.json', 'w') as file:
    json.dump(data, file)

# JSON 읽기
with open('data.json', 'r') as file:
    loaded_data = json.load(file)
    print(loaded_data)

출력(data.json):
json
{"name": "Alice", "age": 30, "is_student": false}

1.1.8. CSV 파일 읽기 및 쓰기

csv 모듈을 사용하면 CSV 파일을 간단히 처리할 수 있습니다.

예제

import csv

# CSV 쓰기
with open('data.csv', 'w', newline='') as file:
    writer = csv.writer(file)
    writer.writerow(['Name', 'Age', 'City'])
    writer.writerow(['Alice', 30, 'New York'])
    writer.writerow(['Bob', 25, 'Los Angeles'])

# CSV 읽기
with open('data.csv', 'r') as file:
    reader = csv.reader(file)
    for row in reader:
        print(row)

출력(data.csv):
['Name', 'Age', 'City']
['Alice', 30, 'New York']
['Bob', 25, 'Los Angeles']

1.1.9. 임시 파일 작업

임시 파일 작업에는 tempfile 모듈을 사용합니다.

import tempfile

with tempfile.TemporaryFile() as temp_file:
    temp_file.write(b"Temporary data")
    temp_file.seek(0)
    print(temp_file.read()) # b'Temporary data'

1.1.10. 주요 팁

with 문 사용 : 파일을 열 때 항상 with를 사용하여 자동으로 파일을 닫도록 합니다.

경로 처리 : 파일 경로는 os.path 모듈을 사용하여 플랫폼 독립적으로 처리하세요.

대용량 파일 처리 : 대용량 파일은 메모리 절약을 위해 한 줄씩 읽는 방식을 사용하세요.

with open('large_file.txt', 'r') as file:
    for line in file:
        print(line.strip())

 

 

 

1.2. 예외(Exception)란?

Python의 예외 처리(Exception Handling)는 프로그램 실행 중 발생하는 오류를 감지하고, 이를 처리하여 프로그램이 중단되지 않고 정상적으로 작동하도록 하는 메커니즘입니다.

예외 처리는 프로그램의 안정성을 높이고, 오류 상황에서 적절한 조치를 취할 수 있도록 도와줍니다.

예외는 프로그램 실행 중 발생하는 오류를 말하며, 다음과 같은 종류가 있습니다:

  • 구문 오류(SyntaxError) : 코드의 문법이 잘못된 경우.
  • 런타임 오류(RuntimeError) : 실행 중 발생하는 오류 (예: 나누기 0, 잘못된 파일 접근).
  • 논리 오류(Logical Error) : 코드가 실행되지만 원하는 결과를 얻지 못하는 경우.

1.2.1. Python의 예외 처리 구조

Python에서 예외 처리를 위해 사용하는 키워드는 다음과 같습니다:

  • try : 예외가 발생할 가능성이 있는 코드를 실행.
  • except : 예외가 발생했을 때 실행할 코드 블록.
  • else : 예외가 발생하지 않을 때 실행할 코드 블록 (선택 사항).
  • finally : 예외 발생 여부와 관계없이 항상 실행할 코드 블록 (선택 사항).

예외 처리 기본 구조

try:
    # 예외가 발생할 가능성이 있는 코드
    risky_code()
except SomeException:
    # 예외를 처리하는 코드
    handle_exception()
else:
    # 예외가 발생하지 않았을 때 실행되는 코드
    success_code()
finally:
    # 항상 실행되는 코드 (리소스 정리 등)
    cleanup_code()

1.2.2. 예외 처리 예제

1) 기본 예외 처리

try:
    num = int(input("Enter a number: "))
    result = 10 / num
    print(f"Result is {result}")
except ZeroDivisionError:
    print("Error: Cannot divide by zero!")
except ValueError:
    print("Error: Invalid input! Please enter a number.")

실행 결과 (입력값에 따라 달라짐):

입력값이 0인 경우:
Enter a number: 0
Error: Cannot divide by zero!

숫자가 아닌 값을 입력한 경우:
Enter a number: abc
Error: Invalid input! Please enter a number.

2) else와 finally 사용

try:
    num = int(input("Enter a number: "))
    result = 10 / num
except ZeroDivisionError:
    print("Error: Cannot divide by zero!")
except ValueError:
    print("Error: Invalid input! Please enter a number.")
else:
    print(f"Result is {result}") # 예외가 없을 때 실행
finally:
    print("Execution completed.") # 항상 실행

실행 결과:
정상 입력:
Enter a number: 2
Result is 5.0
Execution completed.

0 입력:
Enter a number: 0
Error: Cannot divide by zero!
Execution completed.

3) 모든 예외 처리

특정 예외를 처리하는 대신, 모든 예외를 포괄적으로 처리할 수도 있습니다.

try:
    risky_code()
except Exception as e: # 모든 예외를 포괄적으로 처리
    print(f"An error occurred: {e}")

4) 사용자 정의 예외

Python에서는 개발자가 사용자 정의 예외를 만들 수 있습니다.

이를 통해 프로그램의 특정 상황에 대한 예외를 처리할 수 있습니다.

사용자 정의 예외 클래스

class NegativeNumberError(Exception):
    """Raised when a negative number is encountered."""
    pass

사용 예제

def check_positive(number):
    if number < 0:
        raise NegativeNumberError("Negative number is not allowed!")

    try:
        num = int(input("Enter a positive number: "))
        check_positive(num)
    except NegativeNumberError as e:
        print(e)
    except ValueError:
        print("Please enter a valid number!")

실행 결과:
음수 입력:
Enter a positive number: -5
Negative number is not allowed!

정상 입력:
Enter a positive number: 10

1.2.3. 예외 발생시키기

Python에서는 raise 키워드를 사용하여 의도적으로 예외를 발생시킬 수 있습니다.

예제: 예외 발생

try:
    age = int(input("Enter your age: "))
    if age < 0:
        raise ValueError("Age cannot be negative!")
except ValueError as e:
    print(e)

실행 결과:
정상 입력:
Enter your age: 25

음수 입력:
Enter your age: -3
Age cannot be negative!

1.2.4. 예외 처리의 활용

1) 파일 처리

try:
    with open("data.txt", "r") as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print("Error: The file was not found!")
finally:
    print("Finished file operation.")

2) 리소스 정리

finally는 파일, 데이터베이스, 네트워크 연결 등의 리소스를 항상 정리하는 데 사용됩니다.

try:
    conn = connect_to_database()
    # Database operations
except DatabaseError as e:
    print(f"Database error: {e}")
finally:
    conn.close() # 항상 실행

1.2.5. Best Practices

구체적인 예외 처리:

가능한 한 구체적인 예외를 처리합니다. 예를 들어, ZeroDivisionError, ValueError 등.

모든 예외를 처리하지 않기:

except Exception으로 모든 예외를 처리하지 않도록 주의합니다. 이는 디버깅을 어렵게 만들 수 있습니다.

예외 메시지 제공:

사용자 정의 예외나 raise를 사용할 때는 명확한 메시지를 제공하세요.

finally로 리소스 정리:

파일, 네트워크 연결 등의 리소스를 항상 정리하세요.

 

2. 예제

 

 

Ex. 1. 바탕화면에 '매수종목1.txt' 파일을 생성한 후 다음과 같이 종목코드를 파일에 써보세요.

005930

005380

035420

f = open("C:/Users/moonl/OneDrive/Desktop/매수종목1.txt", mode="wt", encoding="utf-8")
f.write("005930\n")
f.write("005380\n")
f.write("035420")
f.close()

 

 

 

Ex. 2. 바탕화면에 '매수종목2.txt' 파일을 생성한 후 다음과 같이 종목코드와 종목명을 파일에 써보세요.

005930 삼성전자

005380 현대차

035420 NAVER

f = open("C:/Users/moonl/OneDrive/Desktop/매수종목2.txt", mode="wt", encoding="utf-8")
f.write("005930 삼성전자\n")
f.write("005380 현대차\n")
f.write("035420 NAVER\n")
f.close()

 

 

Ex. 3. 바탕화면에 '매수종목.csv' 파일을 생성한 후 다음과 같이 종목코드와 종목명을 파일에 써보세요. 인코딩은 'cp949'를 사용해야합니다.

import csv

f = open("C:/Users/moonl/OneDrive/Desktop/매수종목.csv", mode="wt", encoding="cp949", newline='')
writer = csv.writer(f)
writer.writerow(["종목명", "종목코드", "PER"])
writer.writerow(["삼성전자", "005930", 15.59])
writer.writerow(["NAVER", "035420", 55.82])
f.close()

 

 

Ex. 4. 바탕화면에 생성한 '매수종목1.txt' 파일을 읽은 후 종목코드를 리스트에 저장해보세요.

005930

005380

035420

f = open("C:/Users/moonl/OneDrive/Desktop/매수종목1.txt", encoding="utf-8")
lines = f.readlines() # python list

codes = []
for line in lines:
    code = line.strip() #'\n'
    codes.append(code)

print(codes)

f.close()

출력:
['005930', '005380', '035420']

 

 

Ex. 5. 바탕화면에 생성한 '매수종목2.txt' 파일을 읽은 후 종목코드와 종목명을 딕셔너리로 저장해보세요. 종목명을 key로 종목명을 value로 저장합니다.

005930 삼성전자

005380 현대차

035420 NAVER

f = open("C:/Users/moonl/OneDrive/Desktop/매수종목2.txt", encoding="utf-8")
lines = f.readlines()

data = {}
for line in lines:
    line = line.strip() # '\n' 제거
    k, v = line.split()
    data[k] = v

print(data)
f.close()

출력:
{'005930': '삼성전자', '005380': '현대차', '035420': 'NAVER'}

 

 

Ex. 6. 문자열 PER (Price to Earning Ratio) 값을 실수로 변환할 때 에러가 발생합니다. 예외처리를 통해 에러가 발생하는 PER은 0으로 출력하세요.

per = ["10.31", "", "8.00"]

for i in per:
    print(float(i))
per = ["10.31", "", "8.00"]

for i in per:
    try:
        print(float(i))
    except:
        print(0)

출력:
10.31
0
8.0

 

 

Ex. 7. 문자열로 표현된 PER 값을 실수로 변환한 후 이를 새로운 리스트에 저장해보세요.

per = ["10.31", "", "8.00"]

for i in per:
    print(float(per))
per = ["10.31", "", "8.00"]
new_per = []

for i in per:
    try:
        v = float(i)
    except:
        v = 0
    new_per.append(v)

print(new_per)

출력:
[10.31, 0, 8.0]

 

 

Ex. 8. 어떤 값을 0으로 나누면 ZeroDivisionError 에러가 발생합니다. try ~ except로 모든 에러에 대해 예외처리하지 말고 ZeroDivisionError 에러만 예외처리해보세요.

try:
    b = 3 / 0
except ZeroDivisionError:
    print("0으로 나누었음")

출력:
0으로 나누었음

 

 

Ex. 9. 다음과 같은 코드 구조를 사용하면 예외 발생 시 에러 메시지를 변수로 바인딩할 수 있습니다.

try:
    실행코드
except 예외 as 변수:
    예외처리코드

리스트의 인덱싱에 대해 에러를 출력해보세요.

data = [1, 2, 3]

for i in range(5)
print(data[i])
data = [1, 2, 3]

for i in range(5):
    try:
        print(data[i])
    except IndexError as e:
        print(e)

출력:
1
2
3
list index out of range
list index out of range

 

 

 

Ex. 10. 파이썬 예외처리는 다음과 같은 구조를 가질 수 있습니다.

try:
    실행 코드
except:
    예외가 발생했을 때 수행할 코드
else:
    예외가 발생하지 않았을 때 수행할 코드
finally:
    예외 발생 여부와 상관없이 항상 수행할 코드

아래의 코드에 대해서 예외처리를 사용하고 try, except, else, finally에 적당한 코드를 작성해봅시다. else와 finally는 적당한 문구를 print하시면 됩니다.

per = ["10.31", "", "8.00"]

for i in per:
    print(float(per))
per = ["10.31", "", "8.00"]

for i in per:
    try:
        print(float(i))
    except:
        print(0)
    else:
        print("clean data")
    finally:
        print("변환 완료")

출력:
10.31
clean data
변환 완료
0
변환 완료
8.0
clean data
변환 완료
​
728x90

'Development Tip' 카테고리의 다른 글

Naver Cloud Platform의 API 인증키 발행방법  (0) 2025.01.17
Naver Cloud Platform의 API 인증키 발행방법  (0) 2025.01.06
Python 강좌 11 - Class  (0) 2024.12.23
Python 강좌 10 - Module  (0) 2024.12.23
Python 강좌 09 - 함수  (0) 2024.12.23