본문 바로가기

카테고리 없음

7-6. 모듈과 패키지 관리

파이썬 모듈과 패키지 관리


 

안녕하세요! 지난 시간에는 파이썬 가상 환경(Virtual Environment)을 통해 프로젝트별로 독립적인 개발 환경을 구축하고 패키지를 관리하는 방법을 알아보았습니다. 이제 여러분은 깔끔하고 충돌 없는 개발 환경을 유지할 수 있게 되었을 거예요!

이번 시간에는 파이썬 코드를 더욱 체계적으로 구성하고 관리하는 방법인 **모듈(Module)**과 **패키지(Package)**에 대해 알아보겠습니다. 프로그램의 규모가 커지면 모든 코드를 하나의 파일에 작성하는 것은 비효율적이고 유지보수가 어려워집니다. 모듈과 패키지는 이러한 문제를 해결하고 코드의 재사용성을 높이는 데 필수적인 개념입니다.

마치 레고 블록처럼, 작은 기능 단위(모듈)로 코드를 만들고, 이 블록들을 종류별로 분류하여 보관함(패키지)에 넣어두는 것과 같다고 생각하시면 됩니다.


Part 1: 모듈(Module) 이해하기

**모듈(Module)**은 파이썬 코드를 담고 있는 하나의 .py 파일입니다. 이 파일 안에는 변수, 함수, 클래스 등이 정의될 수 있습니다.

1. 모듈의 특징 및 목적

  • 코드 재사용: 한 번 작성한 모듈은 다른 파이썬 파일에서 import하여 재사용할 수 있습니다.
  • 코드 조직화: 관련된 기능들을 하나의 파일로 묶어 코드를 논리적으로 조직화합니다.
  • 이름 공간(Namespace) 분리: 각 모듈은 고유한 이름 공간을 가지므로, 다른 모듈과의 이름 충돌을 방지합니다.

2. 모듈 생성 및 사용하기

예시: 간단한 계산 모듈 만들기

먼저, my_calculator.py라는 이름의 파일을 만들고 아래 내용을 저장합니다.

my_calculator.py 파일 내용:

Python
 
# 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 파일 내용:

Python
 
# 파일 이름: 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]

Python
파이썬 예시

[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 파일 내용 (비워두거나 초기화 코드 추가 가능):

Python
 
# my_package/__init__.py
# 패키지가 임포트될 때 실행되는 초기화 코드
print("my_package 패키지가 초기화됩니다.")

# 패키지 임포트 시 바로 접근 가능하도록 노출할 모듈/함수
# from . import math_operations
# from .math_operations import add as package_add

my_package/math_operations.py 파일 내용:

Python
 
# 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 파일 내용:

Python
 
# 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 파일 내용:

Python
 
# 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 파일 내용 (패키지 사용):

Python
 
# 파일 이름: 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]

Python
 
파이썬 예시

[VS Code 에디터 창 - my_package/math_operations.py]

Python
 
# 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]

Python
 
# 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]

Python
 
# 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]

Python
 
# 파일 이름: 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 파일 내용 (수정):

Python
 
# 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 파일 내용 (수정):

Python
 
# 파일 이름: 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 (수정)]

Python
 
# 파일 이름: 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 모듈을 이용한 파일/폴더 경로 조작에 대해 알아보겠습니다.


궁금한 점이 있다면 언제든지 질문해주세요! 다음 포스팅에서 만나요!

반응형