안녕하세요! 지난 시간에는 파이썬 가상 환경(Virtual Environment)을 통해 프로젝트별로 독립적인 개발 환경을 구축하고 패키지를 관리하는 방법을 알아보았습니다. 이제 여러분은 깔끔하고 충돌 없는 개발 환경을 유지할 수 있게 되었을 거예요!
이번 시간에는 파이썬 코드를 더욱 체계적으로 구성하고 관리하는 방법인 **모듈(Module)**과 **패키지(Package)**에 대해 알아보겠습니다. 프로그램의 규모가 커지면 모든 코드를 하나의 파일에 작성하는 것은 비효율적이고 유지보수가 어려워집니다. 모듈과 패키지는 이러한 문제를 해결하고 코드의 재사용성을 높이는 데 필수적인 개념입니다.
마치 레고 블록처럼, 작은 기능 단위(모듈)로 코드를 만들고, 이 블록들을 종류별로 분류하여 보관함(패키지)에 넣어두는 것과 같다고 생각하시면 됩니다.
Part 1: 모듈(Module) 이해하기
**모듈(Module)**은 파이썬 코드를 담고 있는 하나의 .py 파일입니다. 이 파일 안에는 변수, 함수, 클래스 등이 정의될 수 있습니다.
1. 모듈의 특징 및 목적
- 코드 재사용: 한 번 작성한 모듈은 다른 파이썬 파일에서 import하여 재사용할 수 있습니다.
- 코드 조직화: 관련된 기능들을 하나의 파일로 묶어 코드를 논리적으로 조직화합니다.
- 이름 공간(Namespace) 분리: 각 모듈은 고유한 이름 공간을 가지므로, 다른 모듈과의 이름 충돌을 방지합니다.
2. 모듈 생성 및 사용하기
예시: 간단한 계산 모듈 만들기
먼저, my_calculator.py라는 이름의 파일을 만들고 아래 내용을 저장합니다.
my_calculator.py 파일 내용:
# my_calculator.py
PI = 3.14159 # 상수 정의
def add(a, b):
"""두 숫자를 더하는 함수"""
return a + b
def subtract(a, b):
"""두 숫자를 빼는 함수"""
return a - b
def multiply(a, b):
"""두 숫자를 곱하는 함수"""
return a * b
def divide(a, b):
"""두 숫자를 나누는 함수 (0으로 나눌 경우 예외 처리)"""
if b == 0:
raise ValueError("0으로 나눌 수 없습니다.")
return a / b
class Calculator:
"""간단한 계산기 클래스"""
def __init__(self, initial_value=0):
self.value = initial_value
def add_to_current(self, num):
self.value += num
return self.value
if __name__ == "__main__":
# 이 부분은 my_calculator.py가 직접 실행될 때만 동작합니다.
# 다른 파일에서 import될 때는 실행되지 않습니다.
print("my_calculator.py 모듈이 직접 실행되었습니다.")
print(f"PI 값: {PI}")
print(f"10 + 5 = {add(10, 5)}")
이제 이 모듈을 다른 파이썬 파일(main_app.py)에서 임포트하여 사용해봅시다.
main_app.py 파일 내용:
# 파일 이름: main_app.py
# my_calculator.py와 같은 폴더에 있어야 합니다.
# 1. 모듈 전체 임포트
import my_calculator
print("--- my_calculator 모듈 전체 임포트 ---")
print(f"PI 상수: {my_calculator.PI}")
print(f"덧셈: {my_calculator.add(7, 3)}")
print(f"곱셈: {my_calculator.multiply(4, 6)}")
# 모듈 내 클래스 사용
calc = my_calculator.Calculator(100)
print(f"계산기 현재 값: {calc.add_to_current(20)}")
# 2. 모듈에서 특정 함수/변수/클래스만 임포트
from my_calculator import subtract, Calculator as MyCalc # Calculator를 MyCalc로 별칭 지정
print("\n--- my_calculator 모듈에서 특정 기능만 임포트 ---")
print(f"뺄셈: {subtract(10, 2)}")
my_calc_obj = MyCalc(50)
print(f"별칭 계산기 현재 값: {my_calc_obj.add_to_current(15)}")
# 3. 모든 것 임포트 (권장하지 않음)
# from my_calculator import * # 모든 것을 임포트하지만, 이름 충돌 가능성 높음
# print(f"나눗셈: {divide(20, 4)}") # *로 임포트했다면 직접 사용 가능
[VS Code 에디터 창 - main_app.py]

[VS Code 터미널 출력]

if __name__ == "__main__": 블록의 의미:
- my_calculator.py 파일 내부에 있는 if __name__ == "__main__": 블록은 해당 스크립트가 직접 실행될 때만 그 안의 코드가 동작하도록 합니다.
- 다른 파일에서 import my_calculator와 같이 임포트될 때는 이 블록 안의 코드는 실행되지 않습니다. 이는 모듈이 다른 곳에서 재사용될 때 불필요한 코드가 실행되는 것을 방지합니다.
Part 2: 패키지(Package) 이해하기
**패키지(Package)**는 여러 모듈들을 체계적으로 묶어놓은 **디렉토리(폴더)**입니다. 패키지는 모듈들을 계층적으로 구성하여 이름 충돌을 방지하고, 대규모 프로젝트를 관리하는 데 유용합니다.
1. 패키지의 특징 및 목적
- 계층적 구조: 관련 모듈들을 하위 디렉토리로 묶어 관리할 수 있습니다.
- 이름 충돌 방지: 다른 패키지에 같은 이름의 모듈이 있어도 충돌하지 않습니다.
- 대규모 프로젝트 관리: 복잡한 시스템을 논리적인 단위로 분할하여 개발 및 유지보수를 용이하게 합니다.
2. 패키지 생성 및 __init__.py 파일
패키지로 인식되려면 디렉토리 내부에 __init__.py 파일이 존재해야 합니다. 이 파일은 해당 디렉토리가 파이썬 패키지임을 알리는 역할을 합니다. (파이썬 3.3부터는 __init__.py 파일이 없어도 패키지로 인식되지만, 여전히 많은 경우에 사용되며, 패키지 초기화 코드를 넣는 용도로 활용됩니다.)
패키지 구조 예시:
my_project/
├── main_app.py
└── my_package/
├── __init__.py
├── math_operations.py
└── string_operations.py
└── sub_package/
├── __init__.py
└── data_processing.py
my_package/__init__.py 파일 내용 (비워두거나 초기화 코드 추가 가능):
# my_package/__init__.py
# 패키지가 임포트될 때 실행되는 초기화 코드
print("my_package 패키지가 초기화됩니다.")
# 패키지 임포트 시 바로 접근 가능하도록 노출할 모듈/함수
# from . import math_operations
# from .math_operations import add as package_add
my_package/math_operations.py 파일 내용:
# my_package/math_operations.py
def add_numbers(x, y):
return x + y
def subtract_numbers(x, y):
return x - y
my_package/string_operations.py 파일 내용:
# my_package/string_operations.py
def reverse_string(s):
return s[::-1]
def capitalize_words(s):
return s.title()
my_package/sub_package/data_processing.py 파일 내용:
# my_package/sub_package/data_processing.py
def process_list(data_list):
return [item * 2 for item in data_list]
def filter_data(data_list, threshold):
return [item for item in data_list if item > threshold]
3. 패키지 내 모듈 임포트 및 사용하기
main_app.py 파일 내용 (패키지 사용):
# 파일 이름: main_app.py
# my_project/main_app.py
# 1. 패키지 내 특정 모듈 임포트
import my_package.math_operations
from my_package.string_operations import reverse_string
# 2. 서브 패키지 내 모듈 임포트
from my_package.sub_package import data_processing
print("--- 패키지 내 모듈 사용 ---")
print(f"덧셈 (math_operations): {my_package.math_operations.add_numbers(10, 5)}")
print(f"문자열 뒤집기 (string_operations): {reverse_string('Python')}")
my_list = [1, 2, 3, 4, 5]
print(f"리스트 처리 (data_processing): {data_processing.process_list(my_list)}")
print(f"데이터 필터링 (data_processing): {data_processing.filter_data(my_list, 3)}")
# 3. __init__.py를 통해 노출된 기능 사용 (만약 __init__.py에 정의했다면)
# from my_package import package_add
# print(f"패키지 __init__ 노출 덧셈: {package_add(20, 10)}")
[VS Code 에디터 창 - my_package/__init__.py]

[VS Code 에디터 창 - my_package/math_operations.py]
# my_package/math_operations.py
def add_numbers(x, y):
return x + y
def subtract_numbers(x, y):
return x - y
[VS Code 에디터 창 - my_package/string_operations.py]
# my_package/string_operations.py
def reverse_string(s):
return s[::-1]
def capitalize_words(s):
return s.title()
[VS Code 에디터 창 - my_package/sub_package/data_processing.py]
# my_package/sub_package/data_processing.py
def process_list(data_list):
return [item * 2 for item in data_list]
def filter_data(data_list, threshold):
return [item for item in data_list if item > threshold]
[VS Code 에디터 창 - main_app.py]
# 파일 이름: main_app.py
# my_project/main_app.py
# 1. 패키지 내 특정 모듈 임포트
import my_package.math_operations
from my_package.string_operations import reverse_string
# 2. 서브 패키지 내 모듈 임포트
from my_package.sub_package import data_processing
print("--- 패키지 내 모듈 사용 ---")
print(f"덧셈 (math_operations): {my_package.math_operations.add_numbers(10, 5)}")
print(f"문자열 뒤집기 (string_operations): {reverse_string('Python')}")
my_list = [1, 2, 3, 4, 5]
print(f"리스트 처리 (data_processing): {data_processing.process_list(my_list)}")
print(f"데이터 필터링 (data_processing): {data_processing.filter_data(my_list, 3)}")
[VS Code 터미널 출력]

Part 3: 상대 경로 임포트 (Relative Imports)
패키지 내부의 모듈에서 같은 패키지 또는 하위/상위 패키지의 다른 모듈을 임포트할 때는 상대 경로 임포트를 사용할 수 있습니다. 이는 패키지의 구조가 변경될 때 임포트 문을 덜 수정해도 되는 장점이 있습니다.
- .: 현재 패키지 내의 모듈을 의미합니다.
- ..: 상위 패키지의 모듈을 의미합니다.
예시: my_package/math_operations.py에서 string_operations를 임포트 (비권장)
일반적으로 math_operations와 string_operations는 서로 다른 종류의 기능을 제공하므로 직접 임포트할 필요는 없지만, 예시를 위해 보여줍니다.
my_package/math_operations.py 파일 내용 (수정):
# my_package/math_operations.py (수정)
# 같은 패키지 내의 string_operations 모듈 임포트
from . import string_operations # .은 현재 패키지를 의미
def add_numbers(x, y):
return x + y
def subtract_numbers(x, y):
return x - y
def perform_and_reverse(x, y):
"""숫자를 더하고 결과를 문자열로 뒤집는 함수 (string_operations 사용)"""
sum_result = add_numbers(x, y)
return string_operations.reverse_string(str(sum_result))
main_app.py 파일 내용 (수정):
# 파일 이름: main_app.py (수정)
# my_project/main_app.py
import my_package.math_operations
# from my_package.string_operations import reverse_string # 이제 필요 없음
print("--- 상대 경로 임포트 사용 예시 ---")
print(f"숫자 더하고 뒤집기: {my_package.math_operations.perform_and_reverse(123, 456)}")
[VS Code 에디터 창 - main_app.py (수정)]
# 파일 이름: main_app.py (수정)
import my_package.math_operations
print("--- 상대 경로 임포트 사용 예시 ---")
print(f"숫자 더하고 뒤집기: {my_package.math_operations.perform_and_reverse(123, 456)}")
[VS Code 터미널 출력]

Part 4: 모듈/패키지 관리 팁
- 명확한 이름: 모듈과 패키지 이름은 그 안에 포함된 기능이 무엇인지 명확하게 나타내야 합니다. (예: utils.py, database_manager.py)
- 작은 단위 유지: 모듈은 너무 커지지 않도록 관련 기능만 포함하는 것이 좋습니다.
- 순환 임포트(Circular Imports) 피하기: 두 모듈이 서로를 임포트하는 경우(A.py가 B.py를 임포트하고, B.py가 A.py를 임포트) 문제가 발생할 수 있습니다. 설계 단계에서 이를 피하도록 노력해야 합니다.
- __init__.py 활용: 패키지 초기화 코드, 또는 패키지 임포트 시 외부로 노출하고 싶은 하위 모듈/함수를 정의하는 데 사용될 수 있습니다.
- pip와 requirements.txt: 외부 패키지 관리는 pip와 requirements.txt를 통해 가상 환경에서 체계적으로 수행합니다.
마무리하며
이번 시간에는 파이썬 코드를 체계적으로 구성하고 관리하는 **모듈(Module)**과 패키지(Package), 그리고 상대 경로 임포트에 대해 자세히 알아보았습니다.
- 모듈: 하나의 .py 파일로, 코드 재사용과 조직화에 사용됩니다.
- 패키지: 여러 모듈을 담는 디렉토리로, __init__.py 파일을 포함하여 계층적인 구조를 만듭니다.
- import 문: 모듈이나 패키지의 내용을 현재 파일로 가져와 사용합니다.
- 상대 경로 임포트: 패키지 내부에서 다른 모듈을 임포트할 때 ., ..를 사용하여 경로를 지정합니다.
모듈과 패키지 관리는 대규모 파이썬 프로젝트를 성공적으로 개발하고 유지보수하는 데 필수적인 기술입니다. 이제 여러분은 복잡한 프로그램도 효율적으로 분할하고 관리할 수 있는 기반을 다지게 되었습니다.
이것으로 '파이썬 고급 문법 & 실전 예제' 챕터의 세 번째 포스팅이 마무리됩니다. 다음 포스팅에서는 파이썬에서 파일을 다루는 또 다른 유용한 방법인 os 모듈과 pathlib 모듈을 이용한 파일/폴더 경로 조작에 대해 알아보겠습니다.
궁금한 점이 있다면 언제든지 질문해주세요! 다음 포스팅에서 만나요!