ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • __init__.py 톺아보기
    언어/파이썬 2023. 8. 12. 20:56

    들어가기 전에

    파이썬으로 작업할 때 종종 __init__.py 를 볼 때가 있습니다. 어떤 역할을 하는 것 인지 유추하기 위해 파일을 클릭해봐도 빈 파일이거나 알 수 없는 __all__ = ['이상한', '문자열'] 등이 있거나 from .module import SomeClass 와 같이 알 수 없는 import 를 하는 코드만 나와있습니다. 어떤 역할을 하는 것인지 알 수 없어 __init__.py 의 역할을 톺아보는 시간을 이번 포스팅에서 갖겠습니다.

    __init__.py 를 왜 사용할까?

    1. 디렉토리를 패키지로 인식 시키기 위해 많은 글들을 보면 __init__.py 를 사용하므로써 파이썬에게 디렉토리가 패키지임을 알려주는 파일이라고 합니다. 하지만 이런 설명은 패키지와 디렉토리와 같은 개념을 알아야 이해할 수 있습니다.
      • 디렉토리는 파일 시스템의 폴더입니다. 예를들어 다음과 같은 구조가 있다고 가정해보겠습니다.
      my_project/
          main.py
          utils.py
          data/
              data.csv
      • 여기서 my_projectdata 폴더는 디렉토리 입니다.
      패키지
      • my_project__init__.py 가 추가되었습니다. 이제 my_project 는 패키지가 됩니다.
      __init__.py 가 붙으나 마나 그게 무슨 상관인데?
      • 파이썬 3.3 이전 버전에서는 __init__.py 를 가 붙지 않은 디렉토리의 모듈을 사용하려고 하면 에러가 발생하였습니다. 예를들어 다음과 같은 코드가 있다고 가정해보겠습니다.
      • my_package/
          module_a.py
          module_b.py
      • 3.3 이전 버전에서는 다음 코드를 실행하면 에러가 발생합니다.
      • from my_package import module_a

        ModuleNotFoundError: No module named 'my_package'
    2. my_project/
         __init__.py
         main.py
         utils.py
         data/
             data.csv
    3. 디렉토리
    하지만 3.3 이상 버전부터는 `__init__.py` 가 없어도 파이썬이 패키지로 인식하기 때문에 문제가 없습니다. 단, 하위 호환성을 위해 이런 컨벤션을 지 키기도 합니다.(그런데 3.3 이전 버전을 어떤 이유로 쓰실까요 ㅎㅎ. 크리티컬한 문제가 아니면 빠르게 업데이트 하시는게 좋을지도.....?)
    ​
    따라서 1번의 이유는 3.3 이하 버전에만 해당 하는 설명입니다.
    1. 패키지 수준 변수 및 함수 정의예시로 다음의 코드를 들 수 있습니다.
    2. # 폴더 구조
      circle/
      __init__.py
         area.py
      main.py
         
      # __init__.py
      print("CIRCLE IS INITIALIZED!")
      RADIUS = 3
      PI = 3.14

      # area.py
      import circle

      def print_area():
       print(RADIUS*RADIUS*PI)
       
      # main.py
      from circle import print_area

      print_area()



      # output
      "CIRCLE IS INITIALIZED!"
      28.26
    3. __init__.py 파일 내에서 패키지 수준의 변수나 함수를 정의할 수 있으며, 패키지를 임포트 하거나 패키지 하위의 서브 패키지 및 모듈을 임포트할 때 초기화 됩니다.
    4. 하위 모듈의 임포트 제어패키지 구조와 코드가 다음처럼 되어 있다고 해보겠습니다.만약 __init__.py 에 아무것도 추가해주지 않았다면 다음처럼 사용해야 합니다.
    5. from my_package.module_a import function_a
      from my_package.module_b import function_b
    6. my_package/
         __init__.py
         module_a.py
         module_b.py
      main.py
         
      # __init__.py
      from .module_a import function_a
      from .module_b import function_b

      __all__ = ['function_a', 'function_b']

      # main.py
      from my_package import function_a, function_b
    7. __init__.py 파일을 사용하면 패키지 내의 특정 모듈만 외부로 노출시킬 수 있습니다. 이를 통해 패키지의 내부 구조를 숨기고 API 를 깔끔하게 유지할 수 있습니다.

    이렇게 __init__.py 를 왜 사용하는지 알아보았습니다. 추가적으로 __init__.py 에 자주 사용되는 __all__ 을 살펴보겠습니다.

    __all__ 변수는 패키지 내의 모듈에서 from <module> import * 형태의 임포트를 수행할 때 어떤 심볼(변수, 함수, 클래스 등)이 임포트될지 지정하는 데 사용됩니다.

    __all__ 변수는 문자열의 리스트로, 해당 모듈에서 임포트하고자 하는 심볼의 이름을 나열합니다.

    예를 들어, 아래와 같은 패키지 형태와 모듈이 있다고 가정해봅시다:

    my_package
    ├── __init__.py
    └── my_module.py
    main.py
    ​
    # my_module.py
    def function_a():
        print("function A")
    ​
    def function_b():
        print("function B")
    ​
    def function_c():
        print("function C")
        
    # __init__.py
    from .my_module import (function_a, function_b, function_c)
    ​
    __all__ = ["function_a", "function_b"]
    ​
    # main.py
    from my_package import *
    ​
    function_a()  # 출력: Function A
    function_b()  # 출력: Function B
    function_c()  # NameError: name 'function_c' is not defined

    __all__ 변수를 사용하면 모듈의 사용자가 임포트할 수 있는 심볼을 제한하거나 명확하게 지정할 수 있으므로, API를 깔끔하게 유지하고 내부 구현을 숨기는 데 유용합니다.

    '언어 > 파이썬' 카테고리의 다른 글

    bisect  (0) 2021.03.08
    Variable Scope  (0) 2021.01.30
    중첩 함수(Nested Function)  (0) 2021.01.24
    가변객체 불변객체  (0) 2021.01.24
    파이썬은 왜 느릴까?  (0) 2021.01.21

    댓글