Module & Package [Wecode][210809]

Jungsoo kim·2021년 8월 10일
0

wecode

목록 보기
10/30

이번에는 Python의 Modeule & Package에 대해서 알아보려고 한다.

<목차>
1. 모듈이란?
2. 모듈 만들기 & 호출 방법
3. 패키지란?
4. sys.modules 와 sys.path의 차이점
5. Apsolute path와 relative path의 차이점
6. 예제 패키지 만들기

1. 모듈이란?

파이썬에서 모듈은 변수, 함수 & 클래스 등을 모아놓은 파일이다.

모듈을 따로 모아서 파일로 보관하는 이유는 보통 다음과 같다.

  1. 다른 파일에서도 모듈에 포함된 변수, 함수 등을 사용하고 싶어서
  2. 전체 코드가 하나의 파일에 넣기는 너무 커져서 여러개로 나누어서 정리를 하기 위해서

2. 모듈 만들기 & 호출 방법

Module을 만드는 방법은 매우 간단하다.

단순히 폴더 안에 파일을 만든 후 그 안에 재사용 하고 싶은 함수나 클래스 등을 구현 하면 된다.

호출 방법은 import라는 키워드를 사용하면 된다.

예를들어, 아래와 같이 my_module이라는 모듈은 만을었을 때

import my_module 명령어를 입력하여 호출 할 수 있다.

모듈을 호출 한 후에는 모듈 안에 있는 변수, 함수 & 클래스 등을 사용할 수있으며, 입력 방식은 아래와 같다.

<모듈 이름>.<모듈에서 사용하기 원하는 변수, 함수 & 클래스 이름>

--> my_module.my_module_func()

주의해야할 점은 반드시 모듈의 이름을 호출하기 원하는 변수, 함수 앞에 붙여줘야 한다는 것이다.

덧붙여, import키워드 이외에도 다른 형식(from ... import...)의 키워드를 사용하여 모듈을 불러들일 수 있다.

예시 코드는 아래와 같다.

위 방식으로 모듈에 포함되어 있는 변수, 함수 & 클래스를 호출 할 경우에는 변수, 함수등을 호출 할 때 모듈의 이름을 앞에 붙여주지 않아도 된다는 장점이 있다.

덧붙여, 여러 모듈을 import해서 사용해야 될 경우, 각 모듈 안에 포함되어 있는 함수의 이름이 동일하게 작성되어 충돌이 일어 날 경우가 있다.

이런 경우에는 import as 키워드를 사용하여 문제를 해결 할 수 있다.
import as 키워드를 사용하면 내가 사용하고자 하는 변수, 함수 & 클래스를 새로운 이름에 할당해서 사용 할 수 있ㄲ따.

예시 코드는 아래와 같다.

3. 패키지란?

패키지는 간단하게 설명하자면 모듈들을 모아놓은 것이라고 할 수 있다.

앞에서 언급했던 것과 같이 모듈은 단순한 파이썬 파일이다. 패키지는 그 파일들을 담고 있는 하나의 폴더라고 생각하면 이해하기 쉽다.

패키지를 사용하는 이유는 모듈에 포함되어 있는 코드들의 양이 너무 커서 한 파일에 보관하기가 힘들 경우, 코드를 여러개의 모듈에 분산해서 보관하고 하나의 패키지 안에서 관리하기 위해서이다.

패키지의 이름은 폴더의 이름과 같아지며, 호출하는 방식은 아래와 같다.

덧붙여, 가끔은 패키지가 import될 때 초기 설정을 해줘야 할 경우가 있는데, 이런 경우에는 패키지에 init.py를 생성하여 해당 파일 안에 초기 설정을 해주면 된다.

패키지 안에 init.py파일이 있으면 패키지가 import될 때 해당 파일의 코드들이 자동으로 먼저 실행된다.

init.py 파일을 통해 할 수 있는 것들은 아래와 같다.

  • Import할 때 경로의 총 길이 줄여주기
    보통의 경우, 패키지 & 모듈에 포함되어 있는 함수를 호출 할 때는 아래와 같이 코드를 작성해 줘야 한다.

    경로의 길이를 줄여주기 위해서는 아래와 같이 코드를 입력해 주면 된다.

  • 패키지에서 import할 수 있는 변수, 함수 & 클래스를 제한하기

  • 패키지가 import될 때 꼭 먼저 실행되어야 하는 코드 실행하기
    import될 때 꼭 먼저 실행되어야 하는 코드는 init.py안에 작성해 주면 된다.

4. sys.modules 와 sys.path의 차이점

먼저 sys.modules에 대해 설명하자면, sys.modules은 이미 built-in되어있는 패키지 & 모듈이나 import된 패키지 & 모듈을 기억하고 있는 곳이다. 따라서, 모듈이나 패키지 명령어가 입력되면 파이썬이 가장 먼저 해당 모듈 & 패키지를 찾는 곳이기도 하다. 즉, 새로 import를 하려고 하는 모듈은 sys.modules에서 찾을 수 없다.

덧붙여, sys.modules은 단순한 dictionary 구조이다.

sys.path는 string요소를 갖고 있는 list이다.
각 string은 파일 경로를 나타내는데 그 경로는 아래와 같다.

위 사진에 있는 경로 안에서 입력받은 패키지 & 모듈이 있는지 찾는다.

파이썬에서 모듈 & 패키지를 찾는 순서는 아래와 같다.

  1. sys.modules
  2. built-in modules
  3. sys.path

5. Absolute path와 relative path 차이점

먼저 Absolute path에 관해 설명하자면, 글자 그대로 절대경로를 의미한다. import하는 모듈 & 패키지의 위치에 상관없이 항상 경로가 동일하기 때문에 절대경로라 한다.

relative path는 상대 경로이며, 절대경로와는 다르게 최상단 디렉토리를 기준으로 경로를 잡는게 아니라 import 하는 위치를 기준으로 경로를 정의한다.

일반적으로 relative path는 local package 안에서 동일선 상에 있는 다른 local package를 import 할때 사용한다. relative path를 사용하는 이유는 절대경로에 비해 경로의 길이가 줄어들기 때문이다.

그러나, 헷갈리기가 쉽고 모듈 & 패키지의 파일, 폴더 위치가 바뀌면 경로 위치도 바꿔줘야 하기 때문에 불편하다. 따라서, 어지간한 경우가 아니면 절대경로를 사용하는 것이 좋을 것 같다.

절대경로와 상대경로를 통해 모듈 & 패키지를 import 하는 것을 아래의 예시와 함께 알아보자.

└── my_app
    ├── main.py
    ├── package1
    │   ├── module1.py
    │   └── module2.py
    └── package2
        ├── __init__.py
        ├── module3.py
        ├── module4.py
        └── subpackage1
            └── module5.py

1. Absolute path

from package1 import module1
from package1.module2 import function1
from package2 import class1
from package2.subpackage1.module5 import function2

절대경로로 my_app 패키지에 포함되어 있는 모듈 & 함수를 import하는 방법은 위와 같다.

2. Relative path

# package2/module3.py

from . import class1
from .subpackage1.module5 import function2

절대 경로를 사용하여 package2의 module3에서 package2의 class1과 package2의 하위 package인 subpackage1의 module5의 function2 함수를 import 하려고 하면 위와 같다.

6. 예제 패키지 만들기

예시로 아래와 같이 calculator란 패키지를 만들어서 몇가지 테스트를 진행해 보았다.

main.py

# absoulte path
# from calculator.add_and_multiply import add_and_multiply 
 
# relative path
from .calculator.add_and_multiply import add_and_multiply
 
if __name__ == '__main__':
    print(add_and_multiply(1,2))
add_and_multiply.py

from .multiplication import multiply
# from calculator.multiplication import multiply
 
def add_and_multiply(a,b):
    return multiply(a,b) + (a+b)
multiplication.py

def multiply(a,b):
    return(a*b)

여기서 몇 가지 테스트를 진행해 보았다.

먼저, main.py 파일에서 add_and_multiply 함수를 위에 예시와 같이 상대경로로 import해서 실행해 보았다.

그 결과는 아래와 같다.

위와 같은 에러가 발생 하는 이유를 찾아본 결과, 상대경로로 호출 시에는 현재 모듈의 이름을 기반으로 한다. 따라서 import한 add_and_multiply모듈의 이름이 __main__이 된다. 거기다 모듈 자체의 이름도 __main__이 돼서 이름이 두 개가 main으로 겹치게되어 에러가 발생하는 것으로 보인다.

따라서, main.py파일에서 모듈을 import하기 위해서는 항상 절대 경로로 해야한다.

마지막으로, add_and_multiply.py에서 multiply 함수를 절대경로와 상대경로로 각각 import해보자 한다.

우선 첫 번째로 상대경로를 사용하여 import했을 때는 결과가 아래와 같다.

from .multiplication import multiply
# from calculator.multiplication import multiply
 
def add_and_multiply(a,b):
    return multiply(a,b) + (a+b)

print(add_and_multiply(1,2))

현재 위치(add_and_multiply.py)와 불러오려고 하는 함수가 포함된 모듈의 위치가 같은 선상이기 때문에 상대경로를 설정해줄 경우 에러가 발생하는 것으로 보인다. 같은 선상에 있기 때문에 굳이 상대경로 설정을 안하고 절대경로로 호출하더라도 거의 같은 경로로 불러올 수 있기 때문이다.

그 예로, multiplication 앞의 dot(.)을 하나 뺀 절대경로로 호출 시에는 잘 작동하는 것을 확인 할 수 있었다.

# from .multiplication import multiply
from multiplication import multiply
 
def add_and_multiply(a,b):
    return multiply(a,b) + (a+b)

print(add_and_multiply(1,2))

위와 거의 마찬가지 이유로 절대경로를 통해 multiplication 모듈을 호출할 경우, calculator 패키지부터 접근하는 것이 아니라 바로 multiplicatin 부터 접근하여 import하면 된다.

참고를 위해 calculator부터 접근하였을 때의 코드 실행 결과를 아래와 같이 첨부한다.

마무리...

  솔직히 모듈 & 패키지의 개념이나 단순 생성, import하는 방법 등은 비교적 쉽게 이해했다. 그러나, 예제 패키지를 만들어서 main.py 파일에서 상대경로로 다른 모듈을 실행하였을 때 오류가 발생하는 이유에 대해서 파악하는 것과 마지막으로 확인한 같은 선상에 있는 다른 모듈의 함수를 import할 때 오류가 발생하는 이유에 대해 파악하는 데 상당히 오랜 고민을 했다. (솔직히 지금도 내가 이해한 것이 확실한 것인지는 모르겠다. 추후에 정확하지 않다고 판단하면 글을 수정해야할 수도 있다. 따라서, 혹시라도 이 글을 보시는 분들은 참고 정도만 하길 바란다.)

정말 쉽지 않은 블로그 정리였던 것 같다. 그래도 이런 경험들이 쌓여 틀림없이 점프 업하는 단계가 올 것이라고 믿는다. 그럼 이만...

profile
어렵지만 꾸준히 차근차근 해 나가자~!

0개의 댓글