C.W.K.
Stream
Lesson 02 of 05 · published

패키지 / __init__.py / __main__.py

~18 min · package, __init__, __main__, namespace-package

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

패키지 = 모듈 디렉토리

디렉토리가 __init__.py (regular 패키지) 포함하거나 namespace 패키지 룰 (3.3+, __init__.py 불필요) 따르면 Python 패키지 됨. 패키지 안 — 파일이 *모듈*, 서브디렉토리가 *서브패키지*. 전체 트리가 한 import 가능 네임스페이스로 동작.

__init__.py — 패키지 setup

mypkg import 하면 Python 이 mypkg/__init__.py 실행. 사용 — (a) 핵심 이름 re-export 해서 호출자가 from mypkg.submodule import Important 대신 from mypkg import Important 가능, (b) 패키지 전반 setup, (c) __version__ 정의. 작게 유지 — __init__ 의 무거운 작업이 모든 import 느리게.

__main__.py — 패키지를 실행 가능하게

패키지 상단에 __main__.py 추가 + python -m mypkg 로 실행 가능. 패키지로 ship 되는 CLI 도구에 유용. python -m pytest, python -m http.server 가 작동하는 이유도 이 패턴.

__all__ — wildcard import 제어

모듈이 __all__ = ["Foo", "bar"] 정의하면 from module import * 가 그 이름들만 import. __all__ 없으면 모든 public 이름 (앞 underscore 없는) export. public API 가 뭔지 공식화하고 싶을 때 유용.

원칙: 앞 underscore (_private) 가진 이름은 컨벤션상 내부 — 언어 강제 X 지만 도구와 사람이 존중. 호출자가 의존하면 안 되는 거에 예약. public 이름은 from mypkg import name 에 잘 읽히게 명명.

Code

작은 패키지 레이아웃·python
# mypkg/
#   __init__.py
#   core.py
#   utils.py
#
# mypkg/__init__.py
# from .core import important_function   # 패키지 레벨 re-export
# __version__ = "1.0.0"
#
# mypkg/core.py
# def important_function():
#     return 42
#
# mypkg/utils.py
# def helper():
#     return "helped"

# 이제 호출자 가능:
# from mypkg import important_function   # __init__.py re-export 덕분에 작동
# from mypkg.utils import helper          # 항상 작동, 전체 path
# print(mypkg.__version__)
__main__.py — 실행 가능 패키지·python
# mypkg/__main__.py
# import sys
# from .core import important_function
#
# def main():
#     args = sys.argv[1:]
#     print("실행 with", args)
#     print("결과:", important_function())
#
# if __name__ == "__main__":
#     main()

# 부모 디렉토리에서 실행:
# python -m mypkg arg1 arg2
#
# 'python -m pytest', 'python -m http.server' 작동하는 방식.
__all__ — public API 노출·python
# mymodule.py
# def public_func():
#     return "hi"
#
# def _internal():
#     return "export 안 됨"
#
# class Public:
#     pass
#
# class _Private:
#     pass
#
# __all__ = ["public_func", "Public"]
#
# 이제 `from mymodule import *` 가 public_func 와 Public 만 import.
# __all__ 없으면 어쨌든 public_func 와 Public 만 import
# (underscore 시작 안 하는 거), 명시적 __all__ 이 더 명확.
Namespace 패키지 — __init__.py 불필요·python
# 현대 Python (3.3+) 이 namespace 패키지 지원 — __init__.py 없이
# 패키지로 다뤄지는 디렉토리. 논리적 패키지가 여러 물리 디렉토리에
# 분산될 때 유용 (예 — 각 plugin 이 네임스페이스 일부 기여하는
# plugin 시스템).
#
# /path1/myorg/plugin_a/...
# /path2/myorg/plugin_b/...
#
# 어느 쪽도 __init__.py 없으면 둘 다 단일 'myorg' 네임스페이스 기여.
#
# 대부분 애플리케이션 코드엔 __init__.py 있는 regular 패키지가 OK +
# 의도 더 명확. namespace 패키지는 라이브러리/프레임워크 기능.

External links

Exercise

패키지 /tmp/calc_pkg/ + __init__.py (coreadd re-export), core.py (add(a, b) 가 합 반환), __main__.py (커맨드라인 인자 둘로 add 호출 + 결과 출력). /tmpsys.path 에 추가. 테스트 — (a) from calc_pkg import add + 호출. (b) python -m calc_pkg 3 4 실행 + 7 출력 확인.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.