파이썬 모듈과 패키지: import, pip, venv, 라이브러리를 쉽게 설명합니다
파이썬 모듈은 확장자 .py인 파일이고, 패키지는 모듈을 담은 폴더, 라이브러리는 이런 패키지들의 묶음입니다. import 문으로 불러오며, 외부 라이브러리는 pip나 uv로 venv 가상 환경에 설치합니다. 가상 환경은 프로젝트마다 라이브러리 버전이 섞이지 않게 분리합니다. Python 3.15에는 import 앞에 lazy를 붙여 실제 사용 시점까지 로딩을 미루는 기능이 추가되었습니다.
파이썬 모듈은 코드를 담은 일반 파일이고, import는 그 안의 함수와 클래스를 가져오는 방법입니다. 모듈이 모여 패키지가 되고, 패키지가 모여 라이브러리가 됩니다. 외부 라이브러리가 프로젝트끼리 충돌하지 않도록 venv라는 가상 환경에 설치합니다. 이 글에서는 이 전체 흐름을 정리합니다. import가 실제로 무엇을 하는지, 패키지의 구조, pip와 venv 사용법, Python 3.15의 지연 임포트까지 다룹니다.
모듈, 패키지, 라이브러리: 차이점
| 개념 | 무엇인가 | 예시 |
|---|---|---|
| 모듈 | 확장자 .py인 파일 하나. 모듈 이름은 확장자를 뺀 파일 이름 | categories.py → import categories |
| 패키지 | 모듈과 __init__.py 파일을 담은 폴더 | expenses/report.py → from expenses.report import build |
| 라이브러리 | 특정 작업을 위한 모듈과 패키지의 완성된 묶음 | requests, pandas, 표준 라이브러리 pathlib |
| 배포 패키지 (PyPI) | pip가 설치하는 아카이브. 안에 패키지들이 들어 있음 | pip install requests |
대화에서는 '라이브러리', '패키지', '모듈'을 섞어 쓰는 경우가 많고, 그래도 괜찮습니다. 기술적으로는 import가 항상 모듈이나 패키지를 불러오고, pip는 PyPI의 배포 패키지를 설치합니다. 그 안에 패키지들이 들어 있습니다.
import의 동작 원리
실제 코드에서 자주 보는 import 형태는 여러 가지입니다.
import math # 모듈 전체, math.sqrt로 사용
from math import sqrt, pi # 일부 이름만 가져오기
import datetime as dt # 별칭 사용
from collections import Counter as C
print(math.sqrt(16), sqrt(9), pi)
print(dt.date.today())
큰 라이브러리는 관례적인 별칭을 씁니다. import numpy as np, import pandas as pd가 대표적입니다. from module import *는 되도록 쓰지 마세요. 이름 공간을 어지럽히고, 이름이 어디서 왔는지 알 수 없게 만듭니다.
import가 실제로 하는 일
sys.modules캐시에서 모듈을 찾습니다. 이미 불러왔다면 그대로 돌려줍니다.- 없다면
sys.path목록의 폴더에서 파일을 찾습니다. 실행 중인 스크립트의 폴더, 표준 라이브러리, 가상 환경의 site-packages 순서입니다. - 찾은 파일을 위에서 아래로 처음부터 끝까지 실행합니다.
- 모듈 객체를 캐시에 넣고 이름에 연결합니다.
여기서 실무적인 결론이 두 가지 나옵니다. 같은 모듈을 다시 import하면 거의 비용이 없습니다. 코드가 두 번 실행되지 않기 때문입니다. 반대로, 모듈의 최상위 코드는 전부 import 시점에 실행됩니다. print나 무거운 계산도 포함됩니다.
import sys
for p in sys.path:
print(p)
print("math" in sys.modules)
if __name__ == "__main__"
import는 파일을 실행하므로, '스크립트로 직접 실행됐는지'와 '모듈로 불러와졌는지'를 구분할 방법이 필요합니다. 그래서 __name__ 변수를 씁니다. 파일을 직접 실행하면 "__main__", import되면 모듈 이름이 됩니다.
# categories.py
def guess(title: str) -> str:
return "식비" if "카페" in title.lower() else "기타"
if __name__ == "__main__":
print(guess("카페 근처 점심")) # python categories.py로 실행할 때만 출력
패키지에서는 대신 패키지 안의 __main__.py 파일을 만들고 python -m expenses로 실행하는 방법을 씁니다.
파이썬 표준 모듈
파이썬은 '배터리가 포함된' 언어입니다. 수백 개의 내장 모듈을 설치 없이 바로 쓸 수 있습니다. 가장 자주 쓰는 모듈은 다음과 같습니다.
| 모듈 | 용도 |
|---|---|
os, sys, pathlib, shutil | 시스템, 경로, 파일 |
json, csv, pickle | 데이터 형식 |
datetime, time, calendar | 날짜와 시간 |
math, random, statistics, fractions | 수학 |
re, string | 텍스트 처리 |
collections, itertools, functools | 자료구조와 이터레이터 |
logging, argparse, subprocess | 로그, 명령줄 인자, 외부 프로그램 실행 |
asyncio, threading | 비동기와 스레드 |
표준 라이브러리의 모듈 이름 전체는 sys.stdlib_module_names(Python 3.10 이상)에서 볼 수 있습니다. 모듈에 무엇이 있는지는 dir(math)와 help(math)로 확인하세요.
직접 만드는 패키지: 프로젝트 구조
모듈이 많아지면 패키지로 묶습니다. 자주 쓰는 구조는 src 레이아웃입니다.
expenses-project/
├── pyproject.toml
└── src/
└── expenses/
├── __init__.py
├── cli.py
├── parsing.py
├── categories.py
└── report.py
패키지 안의 모듈은 패키지 이름으로 서로를 가져오거나(from expenses.categories import guess), 상대 경로로 가져옵니다(from .categories import guess). 상대 import는 패키지 안에서만 동작하며, 파일을 스크립트처럼 직접 실행하면 동작하지 않습니다.
pip: 라이브러리 설치
외부 라이브러리는 PyPI에 있고, 이를 설치하는 도구가 pip입니다. pip는 파이썬과 함께 설치됩니다. 가장 확실한 방법은 인터프리터를 통해 실행하는 것입니다. 그러면 현재 사용하는 파이썬에 정확히 설치됩니다.
python -m pip install requests # 설치
python -m pip install "pandas>=2.3" # 버전 조건 지정
python -m pip install --upgrade requests
python -m pip uninstall requests # 삭제
python -m pip list # 설치된 패키지 목록
python -m pip show requests # 버전과 의존성
python -m pip freeze > requirements.txt
python -m pip install -r requirements.txt
Windows에서는 python 대신 py 런처를 자주 씁니다. pip가 없다면 내장 모듈로 설치할 수 있습니다: python -m ensurepip --upgrade.
자주 쓰는 파이썬 라이브러리
PyPI에는 수십만 개의 패키지가 있지만, 대부분의 프로젝트는 같은 짧은 목록을 씁니다. 처음에는 이 목록에서 고르세요.
| 작업 | 라이브러리 |
|---|---|
| HTTP 요청과 API | requests, httpx |
| 데이터 분석과 표 | pandas, numpy |
| 그래프 | matplotlib |
| 웹 서비스 | fastapi, django, flask |
| 테스트 | pytest |
| 이미지 | pillow (import할 때는 PIL) |
설치 이름과 import 이름이 항상 같지는 않습니다. pip install pillow로 설치하지만 from PIL import Image로 씁니다. opencv-python을 설치하고 cv2를 import하기도 합니다. 설치 직후 import가 실패하면 패키지 문서에서 import 이름을 확인하세요.
Linux에서 라이브러리 설치
최신 Debian과 Ubuntu에서는 시스템 Python에 pip install을 하면 externally-managed-environment 오류가 납니다(PEP 668). 이것은 보호 장치입니다. 시스템 Python은 운영체제의 패키지 관리자가 관리하므로, pip가 건드리면 안 됩니다. 올바른 해결책은 --break-system-packages 옵션이 아니라 가상 환경입니다.
venv: 파이썬 가상 환경
가상 환경은 인터프리터를 가리키는 링크와 자체 site-packages를 가진 별도의 폴더입니다. 이 안에 설치한 라이브러리는 해당 프로젝트에서만 보입니다. 덕분에 한 프로젝트는 Django 4를, 다른 프로젝트는 Django 5를 쓰면서도 서로 충돌하지 않습니다.
venv 모듈은 파이썬에 기본으로 들어 있어서 따로 설치할 필요가 없습니다. 다만 Debian과 Ubuntu에서는 python3-venv 시스템 패키지가 필요할 수 있습니다.
# .venv 폴더에 가상 환경 만들기
python -m venv .venv
# 활성화: Linux, macOS
source .venv/bin/activate
# 활성화: Windows PowerShell
.venv\Scripts\Activate.ps1
# 이제 pip는 .venv 안에 패키지를 설치합니다
python -m pip install requests
python -c "import sys; print(sys.prefix)"
# 가상 환경 빠져나오기
deactivate
활성화하면 터미널 줄 앞에 (.venv)가 나타납니다. 가상 환경 폴더는 git에 올리지 마세요(.gitignore에 .venv/ 추가). 다른 컴퓨터로 옮기지도 않습니다. 대신 의존성 목록을 저장해 두고, 필요할 때 환경을 다시 만듭니다. PowerShell이 활성화 스크립트 실행을 막는다면 현재 사용자에게 허용하세요: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned.
uv와 pyproject.toml
최근 프로젝트는 의존성을 pyproject.toml에 적습니다. 과정에서 쓰는 uv는 가상 환경 생성과 설치를 한 번에 처리합니다. uv add pandas는 패키지를 받아 pyproject.toml에 기록하고, 정확한 버전을 uv.lock에 고정합니다. 동료는 프로젝트를 받아 uv sync만 실행하면 같은 환경을 얻습니다.
[project]
name = "expenses"
version = "0.1.0"
requires-python = ">=3.15"
dependencies = [
"pandas>=2.3",
]
[project.scripts]
expenses = "expenses.cli:main"
지연 임포트: Python 3.15 (PEP 810)
이 주제에서 3.15의 새 기능은 lazy 키워드입니다. 무거운 라이브러리는 로딩이 오래 걸립니다. 과정 강의에서 측정한 결과로는 python:3.15-slim 이미지에서 일반 import pandas가 약 415밀리초, lazy import pandas가 약 13밀리초 걸렸습니다. 도움말(--help)을 보려고 실행하는 CLI 도구에서는 차이가 매우 큽니다.
lazy import pandas as pd
lazy from expenses.report import build_report
def main() -> None:
...
df = pd.read_csv(path) # pandas가 실제로 로드되는 곳은 여기입니다
lazy import는 모듈 대신 프록시 객체(types.LazyImportType)를 이름에 넣고, 실제 import는 그 이름을 처음 사용할 때 일어납니다. 사용하지 않으면 시간도 들지 않습니다.
lazy import의 제약
- 모듈의 최상위 수준에서만 쓸 수 있습니다. 함수, 클래스,
try/except안에 쓰면SyntaxError입니다. lazy from x import *은 허용되지 않습니다.ModuleNotFoundError는 프로그램 시작 시점이 아니라 처음 사용할 때 발생합니다.- 모듈이 가진 부수 효과(플러그인 등록 등)가 나중으로 미뤄집니다.
모든 import를 한꺼번에 지연시키려면 -X lazy_imports=all 옵션이나 PYTHON_LAZY_IMPORTS=all 환경 변수를 씁니다. 예외는 sys.set_lazy_imports_filter()로 지정합니다. 3.15 이전 버전에서도 동작하는 코드를 원하면 모듈 변수 __lazy_modules__ = ["pandas"]를 사용하세요. 3.15는 나열된 import를 지연시키고, 이전 버전은 평범한 import로 실행합니다. 시작 시간이 어디서 드는지는 python -X importtime -c "import pandas"로 확인합니다. 지연 임포트의 효과는 짧게 자주 실행되는 프로그램에서 가장 큽니다. 오래 떠 있는 서버에서는 효과가 거의 없습니다.
자주 하는 실수
ModuleNotFoundError: No module named 'requests'— 라이브러리를 다른 파이썬에 설치했거나 가상 환경이 활성화되지 않았습니다. 같은 인터프리터로python -m pip show requests를 실행해 확인하세요.- 직접 만든 파일 이름이
json.py,random.py,csv.py인 경우 — 스크립트 폴더가sys.path의 맨 앞에 와서 표준 모듈을 가립니다. Python 3.13 이상은 오류 메시지에서 이름을 바꾸라고 안내합니다. 파일 이름을 바꾸고__pycache__폴더를 지우세요. - 순환 import —
a.py가b.py를,b.py가a.py를 import합니다. 공통 부분을 세 번째 모듈로 빼거나, 함수 안에서 import하세요. - pip를 Python 프롬프트(
>>>) 안에서 실행하면SyntaxError가 납니다. pip 명령은 터미널에서 실행합니다.
정리
모듈은 파일이고, 패키지는 모듈의 폴더, 라이브러리는 그 묶음입니다. import는 모듈을 캐시나 sys.path에서 찾아 한 번 실행합니다. 외부 라이브러리는 pip나 uv로 venv 가상 환경에만 설치하세요. 그래야 프로젝트끼리 충돌하지 않고, 환경을 쉽게 재현할 수 있습니다. 이 주제는 과정 강의에서 실습합니다. 지출 관리기를 패키지로 나누고, 의존성을 pyproject.toml에 적고, 지연 임포트로 시작 시간을 줄입니다.
자주 묻는 질문
프로젝트마다 가상 환경을 만들어야 하나요?
네, 그렇게 하는 것이 좋습니다. 프로젝트마다 라이브러리 버전이 다를 수 있으므로, 가상 환경을 쓰면 충돌을 막고 시스템 Python도 깨끗하게 유지할 수 있습니다.
pip와 uv는 무엇이 다른가요?
pip는 패키지만 설치합니다. uv는 가상 환경을 만들고, 의존성을 pyproject.toml에 기록하며, lock 파일에 정확한 버전을 고정합니다. 또한 훨씬 빠릅니다.
설치된 라이브러리 목록은 어떻게 보나요?
원하는 환경에서 python -m pip list를 실행하세요. pip freeze는 같은 목록을 requirements.txt 형식으로 보여 줍니다.
설치된 모듈은 어디에 저장되나요?
현재 환경의 site-packages 폴더에 있습니다. 특정 모듈의 위치는 __file__ 속성으로 확인할 수 있습니다: import requests; print(requests.__file__).
venv 폴더를 다른 컴퓨터로 옮겨도 되나요?
아닙니다. 가상 환경은 해당 컴퓨터의 경로와 인터프리터에 묶여 있습니다. 대신 의존성 목록을 옮기고, 새 컴퓨터에서 환경을 다시 만드세요.