# 모듈 (Module): 단일 .py 파일
# math_utils.py
def add(a, b):
return a + b
# 패키지 (Package): __init__.py를 포함한 디렉토리
# mypackage/
# __init__.py
# module1.py
# module2.py
| 구분 | 모듈 | 패키지 |
|---|
| 형태 | 단일 .py 파일 | __init__.py를 포함한 디렉토리 |
| 예시 | math_utils.py | mypackage/ |
| 용도 | 관련 함수/클래스 그룹화 | 관련 모듈들을 계층적으로 구성 |
# 1. 모듈 전체 import
import math
math.sqrt(16) # 4.0
# 2. 특정 함수/클래스만 import
from math import sqrt, pi
sqrt(16) # 4.0 (math. 접두사 불필요)
# 3. 별칭(alias) 사용
import numpy as np
from datetime import datetime as dt
# 4. 모든 것 import (권장하지 않음)
from math import * # 네임스페이스 오염 위험
# 5. 상대 import (패키지 내부에서)
from .module1 import func1 # 같은 패키지
from ..parent import func2 # 상위 패키지
from .subpackage.module import func3 # 하위 패키지
mypackage/
├── __init__.py # 패키지 초기화 파일
├── module1.py
├── module2.py
└── subpackage/
├── __init__.py
└── module3.py
# mypackage/__init__.py
# 1. 디렉토리를 패키지로 인식시킴 (Python 3.3+ 에서는 선택사항)
# 하지만 명시적으로 작성하는 것이 좋음
# 2. 패키지 초기화 코드 실행
print("mypackage가 로드되었습니다")
# 3. 패키지 레벨에서 접근 가능한 것들 정의
from .module1 import Class1, function1
from .module2 import Class2
# 4. 패키지 버전 등 메타데이터 정의
__version__ = "1.0.0"
__author__ = "Your Name"
# mypackage/__init__.py
# 방법 1: 명시적으로 import
from .module1 import Class1
from .module2 import function2
# 사용자가 간단하게 사용 가능
# from mypackage import Class1, function2
# 방법 2: 서브모듈 노출
from . import module1
from . import module2
# 사용자가 사용
# import mypackage
# mypackage.module1.Class1()
# 방법 3: 패키지 초기화
def init_package():
"""패키지 초기화 함수"""
print("패키지 초기화 중...")
# 패키지 import 시 자동 실행
init_package()
# mypackage/__init__.py
# __all__이 없으면: 모든 공개 이름이 import됨
# __all__이 있으면: __all__에 명시된 것만 import됨
__all__ = ['Class1', 'function1', 'CONSTANT']
from .module1 import Class1, Class2 # Class2는 __all__에 없음
from .module2 import function1, function2 # function2는 __all__에 없음
from .module3 import CONSTANT
# 사용 예시
# from mypackage import * # Class1, function1, CONSTANT만 import됨
# mypackage/__init__.py
# 공개 API만 명시적으로 정의
__all__ = [
'User',
'create_user',
'DEFAULT_CONFIG',
]
# 내부 구현은 숨김
from .models import User, AdminUser # AdminUser는 공개하지 않음
from .utils import create_user, _internal_helper # _internal_helper는 숨김
from .config import DEFAULT_CONFIG, _SECRET_KEY # _SECRET_KEY는 숨김
# 사용자 관점
# from mypackage import * # User, create_user, DEFAULT_CONFIG만 보임
calculator/
├── __init__.py
├── basic.py
├── advanced.py
└── utils.py
# calculator/__init__.py
"""간단한 계산기 패키지"""
__version__ = "1.0.0"
__all__ = ['add', 'subtract', 'multiply', 'divide', 'power']
from .basic import add, subtract, multiply, divide
from .advanced import power
# calculator/basic.py
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):
if b == 0:
raise ValueError("0으로 나눌 수 없습니다")
return a / b
# calculator/advanced.py
def power(base, exp):
return base ** exp
# 사용 예시
from calculator import add, power
result = add(5, 3) # 8
result = power(2, 3) # 8
mylib/
├── __init__.py
├── math/
│ ├── __init__.py
│ ├── basic.py
│ └── advanced.py
├── string/
│ ├── __init__.py
│ └── utils.py
└── io/
├── __init__.py
└── file_handler.py
# mylib/__init__.py
from . import math
from . import string
from . import io
# mylib/math/__init__.py
from .basic import add, subtract
from .advanced import integrate, differentiate
# 사용 예시
from mylib.math import add
from mylib.string.utils import capitalize
mypackage/
├── mypackage/ # 실제 패키지 코드
│ ├── __init__.py
│ ├── module1.py
│ └── module2.py
├── tests/ # 테스트 코드
│ └── test_module1.py
├── README.md # 프로젝트 설명
├── LICENSE # 라이선스
├── setup.py # 빌드 설정 (구식 방법)
└── pyproject.toml # 빌드 설정 (현대적 방법)
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "mypackage"
version = "1.0.0"
description = "간단한 패키지 설명"
readme = "README.md"
requires-python = ">=3.8"
license = {text = "MIT"}
authors = [
{name = "Your Name", email = "your.email@example.com"}
]
keywords = ["package", "example"]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
dependencies = [
"requests>=2.28.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.0",
"black>=22.0",
]
[project.urls]
Homepage = "https://github.com/username/mypackage"
Documentation = "https://github.com/username/mypackage#readme"
Repository = "https://github.com/username/mypackage"
[tool.setuptools.packages.find]
where = ["."]
include = ["mypackage*"]
from setuptools import setup, find_packages
setup(
name="mypackage",
version="1.0.0",
author="Your Name",
author_email="your.email@example.com",
description="간단한 패키지 설명",
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
url="https://github.com/username/mypackage",
packages=find_packages(),
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires=">=3.8",
install_requires=[
"requests>=2.28.0",
],
extras_require={
"dev": ["pytest>=7.0", "black>=22.0"],
},
)
# 1. 빌드 도구 설치
pip install build twine
# 2. 소스 배포판과 휠 생성
python -m build
# 3. 생성된 파일 확인
# dist/
# ├── mypackage-1.0.0.tar.gz # 소스 배포판
# └── mypackage-1.0.0-py3-none-any.whl # 휠 배포판
# 4. PyPI에 업로드 (테스트 서버)
python -m twine upload --repository testpypi dist/*
# 5. PyPI에 업로드 (실제 서버)
python -m twine upload dist/*
# 6. 설치 확인
pip install mypackage
# 개발 모드로 설치 (코드 변경 시 자동 반영)
pip install -e .
# 또는
pip install -e ".[dev]" # 개발 의존성 포함
# __init__.py 없이도 패키지로 인식 가능
# 여러 디렉토리에 분산된 패키지를 하나로 통합
# site-packages/pkg1/
# module1.py
# site-packages/pkg2/
# module2.py
# 두 디렉토리가 하나의 패키지로 인식됨
import pkg1.module1
import pkg2.module2
# 1. 필요한 것만 import
from math import sqrt # 좋음
import math # 나쁨 (전체 모듈 로드)
# 2. 순환 import 방지
# module1.py
from .module2 import func2 # 나쁨 (순환 참조 위험)
# module1.py
def func1():
from .module2 import func2 # 좋음 (지연 import)
return func2()
# 3. 조건부 import
try:
import numpy as np
HAS_NUMPY = True
except ImportError:
HAS_NUMPY = False
# 4. 타입 체크용 import
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .module2 import Class2 # 타입 체크에만 사용, 런타임에는 로드 안됨
# 패키지 초기화 시 설정 로드
# mypackage/__init__.py
import os
from pathlib import Path
# 패키지 루트 경로
PACKAGE_ROOT = Path(__file__).parent
# 설정 파일 경로
CONFIG_PATH = PACKAGE_ROOT / "config.json"
# 리소스 파일 접근
def get_resource_path(relative_path):
return PACKAGE_ROOT / "resources" / relative_path
# 버전 관리
__version__ = "1.0.0"
# 로깅 설정
import logging
logger = logging.getLogger(__name__)