결론: 코드를 파일과 책임 단위로 나누고 명시적으로 가져온다
실용적으로 모듈은 Python 정의와 문장을 담은 .py 파일이고, 패키지는 점으로 구분한 이름으로 import할 수 있게 관련 모듈을 묶은 구조다. 표준 라이브러리는 Python 배포판과 함께 제공되는 모듈·패키지 모음이며, NumPy나 pandas처럼 별도로 설치하는 외부 패키지와 구분한다. 이 글은 표준 라이브러리만 사용한다.
모듈과 패키지의 기본 구조, 검색 경로, 패키지 내부 참조는 Python 공식 튜토리얼의 Modules에서 확인할 수 있다 (2026-08-04 확인).
import 문 네 가지 읽기
import math
import math as mathematics
from math import pi, sqrt
print(math.sqrt(16))
print(mathematics.floor(3.9))
print(round(pi, 3), sqrt(25))
4.0
3
3.142 5.0
import math는 module 객체를 math라는 이름에 연결한다. 출처가 드러나는 math.sqrt가 기본 선택이다.import math as mathematics는 같은 module에 지역 별칭을 붙인다. 널리 통용되거나 이름 충돌을 피하는 별칭만 쓴다.from math import sqrt, pi는 지정한 이름만 현재 namespace에 연결한다. 짧지만 같은 이름을 이미 썼는지 확인해야 한다.
from module import *를 피하는 이유
별표 import는 module이 공개한다고 판단한 여러 이름을 현재 namespace에 한꺼번에 넣는다. 어느 이름이 어디서 왔는지 읽기 어려워지고, 앞서 정의하거나 다른 module에서 가져온 같은 이름을 덮어쓸 수 있다. module의 공개 목록이 변하면 호출 코드의 의미도 예상 밖으로 달라질 수 있다. 대화형 탐색을 제외한 프로그램에서는 module import 또는 명시적인 이름 목록을 사용한다. 별표 import의 __all__ 규칙과 경고는 Python 모듈 튜토리얼의 패키지 import 설명을 참고한다 (2026-08-04 확인).
실습: 분석 함수를 패키지로 분리하기
아래 네 파일을 같은 작업 디렉터리에 만든다. __init__.py는 일반 패키지임을 명확히 하고 사용자가 가져올 공개 함수를 좁힌다. namespace package라는 예외도 있지만 입문 예제에서는 빈 파일이라도 두는 편이 구조를 알아보기 쉽다.
module-practice/
├── app.py
└── sales_tools/
├── __init__.py
└── summary.py
from statistics import fmean
def summarize(values):
numbers = list(values)
if not numbers:
raise ValueError("values must not be empty")
return {
"count": len(numbers),
"mean": round(fmean(numbers), 2),
"maximum": max(numbers),
}
def format_summary(summary):
return (
f"count={summary['count']} "
f"mean={summary['mean']:.2f} "
f"max={summary['maximum']}"
)
from .summary import format_summary, summarize
__all__ = ["format_summary", "summarize"]
앞의 점은 현재 package를 기준으로 한 explicit relative import다. package 내부에서 가까운 모듈 관계를 표현할 때 쓸 수 있다. app.py 같은 최상위 진입점에서는 package 문맥이 없는 상대 import 대신 sales_tools처럼 absolute import를 사용한다.
from sales_tools import format_summary, summarize
def main():
sales = [1200, 950, 1850]
report = summarize(sales)
print(format_summary(report))
return 0
if __name__ == "__main__":
raise SystemExit(main())
파일이 직접 실행되면 __name__은 '__main__'이고, import되면 module의 정규 이름이다. guard 안에 진입 호출을 두면 app을 import해 테스트할 때 보고서가 자동 출력되지 않는다. main 함수로 지역 상태를 가두는 관례는 Python __main__ 공식 문서에서 확인할 수 있다 (2026-08-04 확인).
cd module-practice
python3 app.py
count=3 mean=1333.33 max=1850
Python은 module을 어떻게 찾고 다시 쓰는가
import는 먼저 sys.modules 캐시를 확인하고 없으면 finder와 loader를 통해 module을 찾고 초기화한다. 일반적인 module 검색에는 built-in module과 sys.path에 있는 위치가 관여한다. sys.path의 정확한 초기값은 실행 방식, 환경, 설치 설정에 따라 달라지므로 '항상 현재 폴더만 찾는다'고 단정하면 안 된다. 프로젝트 루트에서 진입점을 실행하고 임의의 sys.path 조작은 피한다.
같은 프로세스에서 정상적으로 같은 이름을 다시 import하면 sys.modules의 기존 module 객체를 사용하므로 top-level code는 보통 첫 import 때 한 번 실행된다. 그러나 importlib.reload로 다시 초기화하거나 sys.modules 항목을 삭제한 뒤 재import하는 등 예외가 있다. 이 캐시는 import 문을 설정 함수처럼 쓰라는 뜻이 아니다. 네트워크 호출, 파일 생성, 큰 계산 같은 부수 효과는 함수 안에 두고 명시적으로 호출한다. import 시스템과 cache의 정확한 설명은 Python import system 레퍼런스의 module cache를 참고한다 (2026-08-04 확인).
순환 import를 피하는 설계
a.py가 b.py를 import하고 b.py가 다시 a.py의 아직 정의되지 않은 이름을 요구하면 partially initialized module 오류나 누락된 attribute를 만날 수 있다. 공통 상수·타입·순수 함수를 세 번째 module로 옮기고 의존 방향을 한쪽으로 만든다. package의 __init__.py에서 모든 하위 module을 무조건 재수출하는 것도 순환을 키울 수 있으므로 공개 API만 작게 유지한다. 함수 내부 지연 import는 특정 선택적 의존이나 무거운 import의 도구가 될 수 있지만, 구조적 순환을 숨기는 기본 해법으로 사용하지 않는다.
데이터 분석용 표준 라이브러리 선택 지도
표준 라이브러리는 Python과 함께 배포되며 일상적인 문제에 이식성 있는 해법을 제공한다. 전체 범주는 Python Standard Library 공식 색인에서 찾을 수 있다 (2026-08-04 확인).
경로와 파일: pathlib로 운영체제에 덜 종속적인 경로를 조립한다. csv와 json은 표 형식·구조화 텍스트 입출력에 쓰며 다음 글에서 자세히 다룬다.
요약과 자료구조: statistics는 평균·중앙값 같은 기초 통계, collections는 Counter·defaultdict 같은 특수 컨테이너, itertools는 지연 반복 조합에 쓴다.
날짜와 시간대: datetime으로 날짜·시각을 표현하고 zoneinfo로 IANA 시간대를 적용한다. naive datetime과 aware datetime을 섞지 말고 데이터의 기준 시간대를 명시한다.
숫자: math는 실수 기반 수학 함수, decimal은 10진 고정소수점과 명시적 반올림 규칙이 필요한 금액 계산에 적합하다.
텍스트: re는 정규 표현식 검색·검증·추출에 쓴다. 복잡한 패턴에는 이름과 테스트를 붙이고 단순 분리는 문자열 메서드를 우선한다.
난수: random은 의사난수 시뮬레이션·표본 추출용이며 Random(seed)로 독립적이고 재현 가능한 흐름을 만들 수 있다. 비밀번호·토큰·인증에는 random 대신 secrets를 사용한다.
측정: time.perf_counter는 짧은 구간의 경과 시간을 재는 고해상도 단조 시계다. 한 번의 값보다 워밍업과 반복 측정, 대표 입력을 사용한다.
random이 보안에 부적합하다는 경고와 secrets의 용도는 random 공식 문서와 secrets 공식 문서를 함께 확인한다. perf_counter의 기준은 time.perf_counter 공식 문서에 있다 (모두 2026-08-04 확인).
선택 예제: 주문 코드와 정확한 금액 집계
import re
from collections import Counter
from decimal import Decimal
from random import Random
ORDER_PATTERN = re.compile(r"^(?P<region>[A-Z]{2})-(?P<number>\d{3})$")
orders = [
{"code": "KR-001", "amount": "19.90"},
{"code": "US-002", "amount": "10.10"},
{"code": "KR-003", "amount": "5.00"},
]
regions = []
total = Decimal("0")
for order in orders:
match = ORDER_PATTERN.fullmatch(order["code"])
if match is None:
raise ValueError(f"invalid order code: {order['code']}")
regions.append(match.group("region"))
total += Decimal(order["amount"])
rng = Random(42)
print("regions:", dict(sorted(Counter(regions).items())))
print("total:", total)
print("sample:", rng.sample([1, 2, 3, 4, 5], k=3))
regions: {'KR': 2, 'US': 1}
total: 35.00
sample: [1, 5, 3]
re는 구조를 검증하며 region을 추출하고, Counter는 빈도를 세며, Decimal은 문자열 금액을 10진수로 합산한다. Random(42)는 이 예제의 표본 결과를 재현하지만 통계적으로 타당한 실험 설계까지 보장하지 않는다. seed와 표본 절차를 분석 기록에 함께 남긴다.
모듈 설계 체크리스트
☐ import * 대신 module 이름 또는 필요한 이름을 명시한다.
☐ 재사용 함수와 실행 진입점을 나누고 main guard로 import 부수 효과를 막는다.
☐ 최상위 코드는 absolute import, package 내부의 명확한 이웃 관계에는 explicit relative import를 사용한다.
☐ top-level import에서 파일 생성·네트워크 요청·큰 계산을 실행하지 않는다.
☐ 공통 코드를 아래 계층으로 분리해 순환 import가 생기지 않는 의존 방향을 유지한다.
☐ 문제에 맞는 표준 라이브러리를 먼저 찾고 외부 패키지는 설치·버전·배포 의존성을 따로 관리한다.
다음 글: CSV·JSON·Parquet 파일 읽고 쓰기
다음 글에서는 표준 라이브러리 csv와 json을 사용해 텍스트 데이터를 안전하게 읽고 쓰는 규칙을 익힌다. 이어서 Parquet의 열 지향 저장 특성과 외부 engine 의존성을 구분해 파일 형식별 선택 기준을 세운다.
참고 자료
Python 공식 튜토리얼: Modules — module, search path, package와 상대 import (2026-08-04 확인)
Python 언어 레퍼런스: The import system — module 검색·적재와 sys.modules cache (2026-08-04 확인)
Python 표준 라이브러리: __main__ — top-level 환경과 main guard 관례 (2026-08-04 확인)
Python Standard Library 공식 색인 — 배포판에 포함된 표준 module·package 목록 (2026-08-04 확인)
Python 표준 라이브러리: datetime와 zoneinfo — 날짜·시각과 IANA 시간대 처리 (2026-08-04 확인)
Python 표준 라이브러리: decimal — 10진 고정소수점과 반올림 제어 (2026-08-04 확인)
댓글 0
댓글을 불러오는 중…