Python 에서 모듈이 패키지인지 확인하는 방법

PythonBeginner
지금 연습하기

소개

이 랩에서는 Python 에서 모듈과 패키지를 구별하는 방법을 배우게 됩니다. 이는 코드를 효과적으로 구성하고 관리하는 데 매우 중요합니다. 이 랩은 my_package라는 패키지를 생성하는 과정을 안내하며, 이 패키지에는 __init__.py 파일과 my_module.py라는 모듈이 포함됩니다.

그런 다음 패키지 외부에서 main.py 스크립트를 생성하여 모듈을 가져와 사용하는 방법을 보여줍니다. 이를 통해 모듈 (Python 코드를 포함하는 단일 파일) 과 패키지 (모듈과 __init__.py 파일을 포함하는 디렉토리 계층 구조) 의 차이점을 설명합니다. 이 랩은 __path__ 속성과 pkgutil.get_loader 메서드를 사용하여 모듈이 패키지인지 확인하는 방법을 이해하기 위한 기초를 다집니다. 이는 후속 단계에서 다루어질 것입니다.

모듈과 패키지 구별하기

이 단계에서는 Python 에서 모듈과 패키지를 구별하는 방법을 배우게 됩니다. 이러한 구별을 이해하는 것은 Python 코드를 효과적으로 구성하고 관리하는 데 매우 중요합니다.

모듈 (Modules)

모듈은 함수 정의, 클래스 또는 변수와 같은 Python 코드를 포함하는 단일 파일 (또는 파일들) 입니다. 모듈은 코드를 재사용 가능한 단위로 구성하는 데 사용됩니다.

패키지 (Packages)

패키지는 관련 모듈을 디렉토리 계층 구조로 구성하는 방법입니다. 패키지는 하나 이상의 모듈 파일과 __init__.py라는 특수 파일을 포함합니다. __init__.py 파일은 비어 있을 수 있지만, 이 파일의 존재는 해당 디렉토리가 패키지로 처리되어야 함을 나타냅니다.

차이점을 설명하기 위해 간단한 예제를 만들어 보겠습니다.

  1. 먼저, ~/project 디렉토리에 my_package라는 디렉토리를 만듭니다. 이것이 우리의 패키지 디렉토리가 됩니다.

    mkdir ~/project/my_package
    
  2. my_package 디렉토리로 이동합니다.

    cd ~/project/my_package
    
  3. my_package 디렉토리 내에 __init__.py라는 빈 파일을 만듭니다. 이 파일은 my_package가 Python 패키지임을 나타냅니다.

    touch __init__.py
    
  4. 이제 my_package 디렉토리 내에 my_module.py라는 파일을 만듭니다. 이것이 우리의 모듈 파일이 됩니다.

    touch my_module.py
    
  5. VS Code 편집기에서 my_module.py를 열고 다음 코드를 추가합니다.

    ## my_module.py
    def greet(name):
        return f"Hello, {name}!"
    
  6. my_module.py 파일을 저장합니다.

  7. 이제 모듈을 사용하기 위해 my_package 디렉토리 외부에서 Python 스크립트를 만들어 보겠습니다. ~/project 디렉토리로 다시 이동합니다.

    cd ~/project
    
  8. ~/project 디렉토리에 main.py라는 파일을 만듭니다.

    touch main.py
    
  9. VS Code 편집기에서 main.py를 열고 다음 코드를 추가합니다.

    ## main.py
    import my_package.my_module
    
    result = my_package.my_module.greet("LabEx User")
    print(result)
    
  10. main.py 파일을 저장합니다.

  11. main.py 스크립트를 실행합니다.

    python main.py
    

    다음과 같은 출력을 볼 수 있습니다.

    Hello, LabEx User!
    

이 예제는 모듈 (my_module.py) 이 패키지 (my_package) 내에서 어떻게 구성되는지 보여줍니다. __init__.py 파일은 Python 이 디렉토리를 패키지로 인식하는 데 필수적입니다.

path 속성 확인

이 단계에서는 Python 패키지에서 __path__ 속성을 확인하는 방법을 배우게 됩니다. __path__ 속성은 디렉토리가 패키지로 처리되는지 아니면 일반 디렉토리로 처리되는지를 나타내는 중요한 지표입니다.

__path__ 속성

Python 이 패키지를 가져올 때, __path__ 속성을 찾습니다. 이 속성이 존재하면 Python 은 해당 디렉토리를 패키지로 취급하고, __path__에 나열된 경로에서 하위 모듈과 하위 패키지를 검색합니다. __path__가 존재하지 않으면 Python 은 해당 디렉토리를 일반 디렉토리로 취급합니다.

이전 단계에서 사용한 my_package 예제를 계속 진행해 보겠습니다.

  1. ~/project 디렉토리로 이동합니다.

    cd ~/project
    
  2. check_path.py라는 새 Python 파일을 만듭니다.

    touch check_path.py
    
  3. VS Code 편집기에서 check_path.py를 열고 다음 코드를 추가합니다.

    ## check_path.py
    import my_package
    
    try:
        print(my_package.__path__)
    except AttributeError:
        print("my_package does not have __path__ attribute")
    
    import my_package.my_module
    
    try:
        print(my_package.my_module.__path__)
    except AttributeError:
        print("my_package.my_module does not have __path__ attribute")
    
  4. check_path.py 파일을 저장합니다.

  5. check_path.py 스크립트를 실행합니다.

    python check_path.py
    

    다음과 유사한 출력을 볼 수 있습니다.

    ['/home/labex/project/my_package']
    my_package.my_module does not have __path__ attribute
    

    출력은 my_package__path__ 속성을 가지고 있음을 보여주며, 이는 패키지로 처리됨을 확인합니다. 반면에 my_package.my_module (모듈) 은 __path__ 속성을 가지고 있지 않습니다.

이러한 구별은 Python 이 코드를 구성하고 가져오는 방식을 이해하는 데 중요합니다. 패키지는 __path__를 사용하여 중첩된 하위 모듈과 하위 패키지를 허용하는 반면, 모듈은 개별 코드 파일을 나타냅니다.

pkgutil.get_loader 사용

이 단계에서는 pkgutil.get_loader를 사용하여 모듈 또는 패키지의 로더 (loader) 를 검색하는 방법을 배우게 됩니다. 로더는 모듈을 로드하는 역할을 하며, pkgutil.get_loader는 이에 접근할 수 있는 편리한 방법을 제공합니다.

로더란 무엇인가? (What is a Loader?)

로더는 모듈을 로드하는 방법을 알고 있는 객체입니다. Python 의 import 메커니즘의 일부입니다. 다양한 모듈 유형 (예: 소스 코드, 컴파일된 코드 또는 확장 모듈) 에 대해 서로 다른 유형의 로더가 존재합니다.

pkgutil.get_loader 사용하기

pkgutil.get_loader 함수는 모듈 또는 패키지 이름을 입력으로 받아 로더 객체를 반환합니다 (해당하는 로더가 발견된 경우). 로더가 발견되지 않으면 None을 반환합니다.

이전 단계에서 사용한 my_package 예제를 계속 진행해 보겠습니다.

  1. ~/project 디렉토리로 이동합니다.

    cd ~/project
    
  2. get_loader_example.py라는 새 Python 파일을 만듭니다.

    touch get_loader_example.py
    
  3. VS Code 편집기에서 get_loader_example.py를 열고 다음 코드를 추가합니다.

    ## get_loader_example.py
    import pkgutil
    
    loader = pkgutil.get_loader("my_package.my_module")
    
    if loader is not None:
        print(f"Loader found for my_package.my_module: {loader}")
    else:
        print("No loader found for my_package.my_module")
    
    loader = pkgutil.get_loader("os")
    
    if loader is not None:
        print(f"Loader found for os: {loader}")
    else:
        print("No loader found for os")
    
    loader = pkgutil.get_loader("nonexistent_module")
    
    if loader is not None:
        print(f"Loader found for nonexistent_module: {loader}")
    else:
        print("No loader found for nonexistent_module")
    
  4. get_loader_example.py 파일을 저장합니다.

  5. get_loader_example.py 스크립트를 실행합니다.

    python get_loader_example.py
    

    다음과 유사한 출력을 볼 수 있습니다.

    Loader found for my_package.my_module: <_frozen_importlib_external.SourceFileLoader object at 0x...>
    Loader found for os: <_frozen_importlib_external.SourceFileLoader object at 0x...>
    No loader found for nonexistent_module
    

    출력은 my_package.my_module와 내장 모듈 os에 대한 로더가 발견되었지만, nonexistent_module에 대한 로더는 발견되지 않았음을 보여줍니다.

이 예제는 pkgutil.get_loader를 사용하여 모듈 또는 패키지를 로드할 수 있는지 확인하고 해당 로더 객체를 검색하는 방법을 보여줍니다. 이는 내부 검사 (introspection) 및 동적 모듈 로딩에 유용할 수 있습니다.

요약

이 Lab 에서는 Python 모듈과 패키지를 구별하는 방법을 배웠습니다. 모듈은 Python 코드를 포함하는 단일 파일인 반면, 패키지는 모듈과 디렉토리를 패키지로 나타내는 __init__.py 파일을 포함하는 디렉토리 계층 구조입니다.

__init__.py 파일과 greet 함수를 포함하는 my_module.py라는 모듈을 사용하여 my_package라는 패키지를 만들었습니다. 그런 다음 패키지 외부에서 main.py 스크립트를 생성하여 my_package 패키지 내의 my_module 모듈에서 greet 함수를 가져와 사용했습니다.