Skip to main content

학습 목표

  • importfrom ... import 구문을 올바르게 사용할 수 있다
  • 절대 경로와 상대 경로 import의 차이를 이해한다
  • __init__.py의 역할과 __all__을 활용할 수 있다
  • 순환 참조(Circular Import)를 식별하고 해결할 수 있다

왜 중요한가

파이썬의 import 시스템은 프로그램 구조를 결정합니다. 머신러닝 프로젝트에서 모델, 데이터 처리, 유틸리티를 모듈로 분리하고, 이들 간의 의존성을 관리하는 것이 프로젝트 확장성의 핵심입니다.

기본 import

# 모듈 전체 import
import math
print(math.pi)          # 3.14159...
print(math.sqrt(16))    # 4.0

# 별칭(alias)으로 import
import numpy as np
import pandas as pd

# 특정 이름만 import
from math import pi, sqrt
print(pi)               # 3.14159...
print(sqrt(16))         # 4.0

# 별칭으로 특정 이름 import
from datetime import datetime as dt
now = dt.now()
from module import *는 사용을 피합니다. 이름 충돌이 발생할 수 있고, 어떤 이름이 어디서 왔는지 추적하기 어렵습니다.
# 비추천
from os.path import *
from math import *  # os.path의 이름과 충돌 가능!

# 추천
import os.path
import math

패키지와 init.py

my_project/
├── __init__.py          # 패키지 초기화 파일
├── models/
│   ├── __init__.py
│   ├── linear.py
│   └── neural.py
├── data/
│   ├── __init__.py
│   ├── loader.py
│   └── transforms.py
└── utils.py
# __init__.py - 패키지 초기화 및 공개 API 정의
# my_project/models/__init__.py

from .linear import LinearModel
from .neural import NeuralNetwork

__all__ = ["LinearModel", "NeuralNetwork"]
# 사용자 코드
from my_project.models import LinearModel
from my_project.data.loader import DataLoader

절대 경로 vs 상대 경로

# 절대 경로 import (권장)
from my_project.models.linear import LinearModel
from my_project.utils import normalize

# 상대 경로 import (패키지 내부에서만 사용)
# models/neural.py에서
from .linear import LinearModel        # 같은 디렉토리
from ..utils import normalize          # 상위 디렉토리
from ..data.loader import DataLoader   # 상위 -> 다른 하위

all

__all__from module import *에서 공개할 이름을 제한합니다.
# utils.py
__all__ = ["normalize", "standardize"]

def normalize(data):
    """공개 함수"""
    pass

def standardize(data):
    """공개 함수"""
    pass

def _internal_helper():
    """비공개 함수 (import *에 포함 안 됨)"""
    pass

순환 참조 해결

# 문제: a.py와 b.py가 서로를 import
# a.py
# from b import func_b  # b가 아직 로드 안 됨 -> ImportError!

# 해결 방법 1: 지연 import (함수 내부에서 import)
# a.py
def func_a():
    from b import func_b  # 함수 호출 시점에 import
    return func_b()

# 해결 방법 2: 구조 리팩토링 (공통 모듈 분리)
# common.py에 공유 코드 배치

# 해결 방법 3: TYPE_CHECKING 가드 (타입 힌트 전용)
from __future__ import annotations
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from b import TypeB  # 런타임에 실행 안 됨

def func_a(param: "TypeB"):
    pass

AI/머신러닝 프로젝트 구조 예시

ml_project/
├── src/
│   ├── __init__.py
│   ├── models/
│   │   ├── __init__.py
│   │   ├── base.py        # BaseModel ABC
│   │   ├── classifier.py  # 분류 모델
│   │   └── regressor.py   # 회귀 모델
│   ├── data/
│   │   ├── __init__.py
│   │   ├── dataset.py     # Dataset 클래스
│   │   └── transforms.py  # 전처리 함수
│   ├── training/
│   │   ├── __init__.py
│   │   ├── trainer.py     # 학습 루프
│   │   └── callbacks.py   # 콜백
│   └── utils/
│       ├── __init__.py
│       ├── metrics.py     # 평가 지표
│       └── logging.py     # 로깅
├── tests/
├── configs/
└── pyproject.toml
Python 3.3 이후 namespace package를 사용하면 __init__.py 없이도 패키지가 됩니다. 하지만 명시적으로 패키지임을 나타내고, 초기화 코드나 공개 API를 정의하기 위해 빈 파일이라도 유지하는 것을 권장합니다.
이 조건은 파일이 직접 실행될 때만(python script.py) 참이 됩니다. import될 때는 거짓이 되어 코드가 실행되지 않습니다. 스크립트의 진입점(Entry Point)을 정의할 때 사용합니다.

체크리스트

  • importfrom ... import를 올바르게 사용할 수 있다
  • __init__.py__all__의 역할을 설명할 수 있다
  • 순환 참조를 식별하고 해결할 수 있다
  • 머신러닝 프로젝트의 모듈 구조를 설계할 수 있다

다음 문서

표준 라이브러리

os, pathlib, datetime, json, re

디자인 패턴

디자인 패턴 복습