파이썬에서 패키지(Package)는 모듈(module)들을 모아놓은 디렉토리이다. 이는 관련된 모듈들을 하나의 이름 공간으로 묶어 관리함으로써 코드의 구조를 체계적으로 만들어 준다. 패키지는 init.py 파일을 포함하는 디렉토리로 정의되며, 이 파일을 통해 해당 디렉토리가 패키지임을 파이썬 인터프리터에 알려준다. 패키지를 사용하면 다른 패키지의 모듈과 이름이 충돌하는 것을 방지하고, 코드의 재사용성을 높이며, 배포 및 관리를 용이하게 할 수 있습니다. 결과적으로 복잡한 프로젝트를 보다 효율적으로 구성하고 유지보수할 수 있게 된다.
파이썬 패키지는 코드를 체계적으로 관리하기 위해 다양한 구조로 활용될 수 있다. 가장 기본적인 형태의 패키지부터, 내부에 또 다른 패키지를 두는 서브 패키지 구조, init.py 파일을 활용하여 임포트 경로를 단순화하는 방법, 그리고 from package import * 사용 시 가져올 모듈을 제어하는 경우까지 여러 가지 상황이 있다.
1. 기본 패키지 구조
가장 일반적인 경우로, 관련된 모듈들을 하나의 디렉토리 아래에 모아놓은 형태다.
구조:my_package/module1.py, my_package/module2.py
my_package/
├── __init__.py
├── module1.py
└── module2.py
# my_package/module1.py
def greet():
print("Hello from module1!")
# my_package/module2.py
def depart():
print("Goodbye from module2!")
패키지 외부의 파이썬 파일에서 다음과 같이 패키지와 모듈 이름을 모두 사용하여 함수를 호출한다.
# main.py
import my_package.module1
import my_package.module2
my_package.module1.greet()
my_package.module2.depart()
2. 서브 패키지 (중첩 패키지)
패키지 안에 또 다른 패키지를 만들어 계층적인 구조로 관리할 수 있습니다. 이는 규모가 큰 프로젝트에서 유용하다.
구조:main_package/sub_package/utils.py
# main_package/sub_package/utils.py
def utility_func():
print("This is a utility function.")
사용법:
전체 경로를 사용하여 서브 패키지의 모듈에 접근한다.
# main.py
from main_package.sub_package import utils
utils.utility_func()
3. init.py를 활용한 임포트 간소화
init.py 파일에 코드를 작성하여 패키지의 특정 함수나 모듈을 패키지 레벨로 끌어올릴 수 있다. 이렇게 하면 사용자는 더 짧은 경로로 함수에 접근할 수 있다.
구조:
simple_pkg/
├── __init__.py
└── calculator.py
# simple_pkg/calculator.py
def add(a, b):
return a + b
# simple_pkg/__init__.py
# calculator 모듈의 add 함수를 simple_pkg 레벨로 가져오기
from .calculator import add
사용법:
# main.py
from simple_pkg import add
result = add(5, 3)
print(result) # 출력: 8
이제 simple_pkg에서 바로 add 함수를 임포트할 수 있다.
4. * 임포트 제어 (all)
from package import * 구문은 기본적으로 패키지의 모든 것을 가져오지 않는다. init.py 파일 안에 all 이라는 리스트를 정의하면 *를 사용해 임포트할 대상을 명시적으로 지정할 수 있다.
구조:
- control_pkg/module_a.py: def func_a(): print(“Function A”)
- control_pkg/module_b.py: def func_b(): print(“Function B”)
- control_pkg/__init__.py:
control_pkg/
├── __init__.py
├── module_a.py
└── module_b.py
# '*'로 임포트할 때 module_a만 공개하도록 설정
__all__ = ['module_a']
사용법:
# main.py
from control_pkg import *
module_a.func_a() # 정상 작동
# module_b.func_b() # NameError: name 'module_b' is not defined
*를 사용하면 __all__에 지정된 module_a만 임포트된다.
패키지를 사용할 때는 몇 가지 주의할 점이 있다. 우선, 순환 참조(circular import)를 피해야 합니다. 두 모듈이 서로를 임포트하는 상황이 발생하면 프로그램이 오류를 일으키므로 패키지 구조 설계 시 이를 반드시 고려해야 한다. 또한, init.py 파일을 남용하여 너무 많은 코드를 넣으면 패키지 로딩 속도가 느려지고 가독성이 떨어질 수 있으므로 주의가 필요하다.
패키지나 모듈의 이름은 파이썬의 표준 라이브러리나 이미 설치된 다른 패키지와 충돌하지 않도록 고유하고 의미 있는 이름으로 짓는 것이 중요하다. 마지막으로, from package import *의 사용은 코드의 출처를 불분명하게 만들 수 있으므로, all 변수를 명시적으로 정의하여 공개할 API를 제한하거나 필요한 모듈만 직접 임포트하는 것이 좋다.