게시:
수정:

하나의 .py 파일에 넣기에 복잡한 코드이거나 다양한 기능으로 분화된 계층 구조를 가진 프로그램을 만드는 경우 기능 단위로 모듈을 만들어 분리하면 프로젝트를 체계적으로 관리할 수 있다.

모듈(Module)

변수, 함수(def) 및 클래스(class) 등을 모아놓은 하나의 파이썬 파일(.py)이다.
비어있는 파이썬 파일에서 모듈을 불러오면 미리 정의되어 있는 변수, 함수, 클래스를 사용할 수 있다.

# example1.py
my_var = "이것은 변수입니다."

def my_add_function():
    return (a + b)
    
def my_subtract_function():
    return (a - b)

class MyModuleClass1:
    pass

패키지(Package)

여러 개의 모듈을 모아놓은 디렉토리(Directory)이다.
거창한 개념이 아니라 패키지는 모듈의 집합으로 모듈의 상위구조 개념인데 파이썬이 패키지로 인식하기 위해서는 __init__.py를 포함하고 있어야만 한다. 모듈과 마찬가지로 비어있는 파이썬 파일에서 패키지를 사용하면 미리 정의되어 있는 함수, 변수 및 클래스를 사용할 수 있다.

project_directory
      ├──── main.py
      ├──── my_package1               ← 패키지(폴더)
      │          ├─ __init__.py       ← 파이썬에게 패키지로 인식시키기 위하여 필요
      │          ├─ my_module1.py     ← 모듈
      │          └─ my_calculator.py  ← 모듈
      └──── my_package2
                 ├─ __init__.py
                 ├─ my_module2.py
                 ├─ my_module3.py
                 └─ sub_package
                         └─ my_module4.py

참고: __init__.py의 역할은 이 디렉토리가 패키지임을 인식시켜주는 역할을 한다. 만약 패키지 디렉토리에 __init__.py 파일이 없으면 파이썬은 이 디렉토리를 패키지로 인식하지 못 한다. 파일 자체는 아무 내용도 없는 빈 파일이다.

How to use

Import

하나의 모듈(.py)을 통째로 불러오는 방식이다. import 키워드 뒤에 모듈명을 입력하여 불러오며 코드 내에서 module_name.object_name 형식으로 사용한다. 이러한 방식을 dot notation이라 한다.

모듈 자체를 불러오기 떄문에 하위 객체를 개별적으로 불러오지 않아도 사용할 수 있는 편리함이 있지만 모듈에 있는 기능을 사용하는 코드를 짤 때 모듈명(module_name.object_name)을 매번 입력해주어야 하는 번거로움이 있다.

# example2.py
import example1


var1 = example1.my_var

example1.my_add_function(10, 20)

my_class = example1.MyModuleClass()

From + import

모듈의 특정 변수, 함수 및 클래스를 지정하여 불러오는 방식이다.
from <module_name> import <object_name1>, <object_name2>... 형식으로 불러온다.

사용할 객체를 구체적으로 지정했기 때문에 한 번 불러온 뒤에는 다시 모듈명을 입력하지 않아 입력이 편리하다. 특정 기능만 필요하거나 집중적으로 사용할 때 유용하다.

import 뒤에 Asterisk(*)를 입력하면 모듈 내 모든 기능을 불러올 수 있지만 이러한 방식은 복잡한 코드에서 Local scope의 함수, 변수 및 클래스명과 충돌할 가능성이 있으므로 좋지 않다.

from example1 import my_subtract, my_divide


my_subtract_function(10, 7)

Import Search 우선순위

1. sys.module

파이썬이 실행된 후 어떠한 패키지나 모듈이 단 한 번이라도 import 됐었다면 저장되는 영역이다.

자주 사용하는 패키지나 모듈이면 이 곳에 저장되어 있을 가능성이 높다. 패키지 및 모듈을 import 하면 파이썬은 이 영역을 가장 먼저 확인하는데 이는 불필요하게 다른 path를 뒤적이는 리소스 낭비를 막는 설계라 생각된다.

sys.modules의 구조는 모듈 이름(key)을 이미 로드된 모듈(value)로 Mapping한 사전(Dictionary) 형태로 되어 있다.

2. built-in modules

파이썬 내장 모듈이다.

파이썬에서 제공하는 공식 라이브러리로 별도의 설치과정없이 사용할 수 있는 모듈이다.
위에서 언급한 sys도 이에 해당하며 이 외에 대표적으로 os, time 등이 있다.

3. sys.path

파이썬이 패키지 및 모듈을 찾을 때 마지막으로 확인하는 영역이다.

여기서 path는 파일이 위치한 경로를 의미하며 파이썬 패키지 관리자(pip)로 설치한 패키지와 새로 만든 모듈은 이곳에 경로가 등록되어 찾을 수 있게 된다.

sys.path의 구조는 문자열 값(str value)으로 구성된 리스트(list) 형태로 라이브러리들이 설치되어 있는 경로를 나타낸다.

경로(Path)

sys.path에 자동으로 저장되는 내장 모듈나 파이썬 패키지 관리자(pip)로 설치한 패키지는 import search에 문제가 없어 import 경로를 지정하기 쉬운 반면 직접 작성한 로컬 패키지는 sys.path에 포함되지 않기 때문에 경로를 아주 정확하게 지정해주어야 한다.

로컬 패키지 import 경로를 지정하는 방법에는 절대경로와 상대경로가 있다. 각각 알아보자.

절대 경로(Absolute Path)

프로젝트 최상위 디렉토리를 기준으로 삼는 경로 표기법이다.
프로젝트 파일 내 어느 곳에서나 같은 pathimport할 수 있다.

로컬 패키지를 import하는 경우에 주로 이 방법을 사용하며 Dot notation으로 경로를 표현한다.
프로젝트 루트 디렉토리(root directory)는 기본적으로 sys.path에 포함되므로 표기 생략한다.

# pkg example
project_directory
      ├──── main.py
      ├──── my_package1
      │          ├─ __init__.py
      │          ├─ my_module1.py
      │          └─ my_calculator.py
      └──── my_package2
                 ├─ __init__.py
                 ├─ my_module2.py
                 ├─ my_module3.py
                 └─ sub_package
                         └─ my_module4.py
# main.py
from package1 import my_module1
from package1.my_module1 import my_add_function
from package2.sub_package.my_module4 import my_sub_function

상대 경로(Relative Path)

호출하는 현재 위치(Current directory)를 기준으로 삼는 경로 표기법이다.
로컬 패키지 내에서 인접한 패키지를 import할 때 주로 사용한다.

현재 위치를 기준으로 상대적인 위치를 표기하므로 선언하는 파일의 path가 변경되면 상대적인 위치도 바뀌기 때문에 당연히 기존의 상대 경로도 사용할 수 없게 된다.

절대 경로와 마찬가지로 Dot notation을 사용하나 현재 위치를 .으로 표기하고 한 단계 상위 디렉토리를 ..으로 표기하여 경로를 지정한다.

# pkg example
project_directory
      ├──── main.py
      ├──── my_package1
      │          ├─ __init__.py
      │          ├─ my_module1.py
      │          └─ my_calculator.py
      └──── my_package2
                 ├─ __init__.py
                 ├─ my_module2.py
                 ├─ my_module3.py
                 └─ sub_package
                         └─ my_module4.py
# my_module2.py
from .my_module3 import MyModuleClass2

# my_module2.py
from .sub_package.my_module4 import function2

# my_module4.py
from ..module2 import function1

참고: main.py에서 하위 패키지 내 모듈을 import하면 아래와 같은 에러가 발생한다.
ImportError: attempted relative import with no known parent package

.py 파일을 대화형 인터프리터로 실행하면 __name__ = '__main__'이 된다. 즉, 인터프리터로 실행하기 위해서 임시로 해당 파일이 메인 파일이 되는 것이다. Relative path 가져오기는 패키지 내에서만 상대적인 것으로 파일 이름이 '__main__'으로 지정되면 파이썬은 가져오려는 모듈이 패키지 안에 있는 것으로 간주하지 않는다.

따라서 main.py가 파이썬을 패키지에 있는 것으로 인식하지 못하기 때문에 알려진 상위 패키지 없이 상대경로로 가져오기를 시도했다는 에러 메시지가 출력되며 상대경로를 사용할 수 없는 것이다.

python import error message image
알려진 상위 패키지 없이 상대경로 가져오기를 시도했다는 에러 메시지가 발생한다.

댓글남기기