TIL[53]. Python_How Import Statement Finds Modules & Packages

jake.log·2020년 8월 23일
0

Python

목록 보기
35/39

34.How Import Statement Finds Modules & Packages

파이썬은 module과 package를 어떻게 찾을까?

1.Import Search 순서

예를 들어, abc 라는 package가 있다고 가정해 보자.
그리고 abc package를 사용하려면 다음처럼 import 해야 한다.

import abc

여기서 abc는 파이썬 파일(모듈일 경우) 이거나 파이썬 파일들을 담고 있는 디렉토리(package의 경우)다.

그러므로 해당 파일이나 디렉토리가 어디있는지 파이썬이 찾을 수 있어야 import가 가능하다.

모듈/package를 어떻게 찾을까?

파이썬은 다음 3가지 장소를 순서대로 보면서 찾습니다.

1. sys.modules:파이썬이 모듈이나 package를 찾기위해 가장 먼저 확인하는 곳

  • 이미 import된 모듈과 package들을 저장
  • 새로 import 하는 모듈은 sys.modules 에서 찾을 수 없다.

2. built-in modules: 파이썬에서 제공하는 파이썬 공식 라이브러리들

  • 파이썬에 포함되어 나오므로 파이썬이 쉽게 찾을 수 있다.

3. sys.path: 마지막으로 보는 장소

  • sys.path는 기본적으로 list이며 string 요소들을 가지고 있는 list.

  • 각 string 요소들은 다음 처럼 경로를 나타낸다:

    ['',
    '/Users/jake/anaconda3/bin',
    '/Users/jake/anaconda3/lib/python36.zip',
    '/Users/jake/anaconda3/lib/python3.6',
    '/Users/jake/anaconda3/lib/python3.6/lib-dynload',
    '/Users/jake/anaconda3/lib/python3.6/site-packages',
    '/Users/jake/anaconda3/lib/python3.6/site-packages/aeosa',
    '/Users/jake/anaconda3/lib/python3.6/site-packages/IPython/extensions',
    '/Users/jake/.ipython']

  • 파이썬은 list의 각 경로를 하나 하나 확인하면서 해당 경로에 import 하고자 하는 package가 위치해 있는지 확인

  • 참고: sys 는 파이썬에 포함되어 있는 모듈.

  • sys 모듈을 import 해서 sys.modules와 sys.path 를 출력할수도 있고 수정 할 수 있다.

import sys

print(sys.path)
print(sys.modules)

2.Absolute Path & Relative Path

직접 개발한 local package를 import 할때는 해당 package의 위치에 맞게 import 경로를 잘 선언해야 한다.

Local package를 import 하는 경로에는 absolute path 와 relative path 가 있다.

  • Absolute path: 이름 그대로 절대 경로, import를 하는 파일이나 경로에 상관없이 항상 경로가 동일하다.

예시:

    ├── main.py
    ├── package1
    │   ├── module1.py
    │   └── module2.py
    └── package2
        ├── __init__.py
        ├── module3.py
        ├── module4.py
        └── subpackage1
            └── module5.py
from package1 import module1
from package1.module2 import function1
from package2 import class1
from package2.subpackage1.module5 import function2

경로들의 시작점이 전부 "my_app" 프로젝트의 가장 최상위 디렉토리에서 시작한다.

예시)
subpackage1의 module5 모듈의 function2 함수를 import 하기 위한 경로

my_app => package2 => subpackage1 => module5.py

이걸 리눅스의 directory 경로 형식

my_app/package2/subpackage1/module5.py

윈도우스 형식
my_app\package2\subpackage1\module5.py

파이썬에서는 slash (/) 나 back slack() 대신에 dot (.) 을 사용해서 경로를 표현

my_app.package2.subpackage1.module5.py

package2.subpackage1.module5.py

from import 키워드를 사용해 import

from package2.subpackage1.module5 import function2

my_app 프로젝트 내에서는 어느 파일, 어느 위치에서 import 하던지 경로가 항상 위와 같이 동일하게 되므로 absolute path 라고 한다.

경로가 길어지는 단점을 보완하기 위해서 relative path를 사용한다.

Relative path 는 import 하는 위치를 기준으로 경로를 정의한다.

그래서 일반적으로 relative path는 local package 안에서 다른 local package를 import 할때 사용된다.

예시) package2의 module3에서 package2의 class1과 package2의 하위 package인 subpackage1의 module5의 function2 함수를 import

#package2/module3.py

from . import class1
from .subpackage1.module5 import function2
  • dot(.)은 import가 선언되는 파일의 현재 위치.

  • 현재위치는 package2/module3.py 이므로 현재 위치에서부터 원하는 모듈의 경로만 선언

  • 또한dot 2개(..) 는 현재위치에서 상위 디렉토리로 가는 경로다.

#subpackage1/module5.py
from ..module4 import class4

Relative path : 경로의 길이를 줄여준다는 장점은 있지만 헷갈리기 쉽고 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점.

Assignment

1.sys.modules 와 sys.path의 차이점을 서술해 주세요.

  • sys. modules 는 파이썬 module, pakage를 찾을 때 제일 처음으로 확인하는 장소다.

  • Dictionary 구조로 되어있으며,한번이라도 import 되어있는 module과 pakage가 저장되어있다.

  • sys.path는 파이썬이 가장 마지막으로 확인하는 장소로 string 요소들을 가지고 있는 list 형식으로 구성되어 있다.

2.sys 도 import 해야하는 모듈입니다. 파이썬은 sys 모듈의 위치를 어떻게 찾을 수 있을까요?

  • sys.modules은 파이썬에 이미 포함 된 module중 하나이다.
  • sys.modules 디렉토리나 sys.path 경로를 확인하여 module의 위치를 확인 할 수 있다.

3. Absolute path와 relative path의 차이점을 서술해 주세요.

  • Absolute path :

    절대적인 경로라고 부른다.
    module이나 package를 import 할때, 최상위 디렉토리에서부터 하위 모듈,패키지까지 정확히 명시해 준다. 보통 local 패키지를 import 할 때 사용하는데 정확히 경로를 파악할 수 있지만, 경로가 길어진다는 단점이 있다.

  • Relative Path:

    상대적인 경로라고 부른다.
    module이나 package를 import 할때, 현재 디렉토리를 기준으로 찾아갈 파일의 상대적인 경로를 명시한다. local package안에 다른 local package를 import할때 사용되며, 경로의 길이를 줄여준다는 장점은 있지만 헷갈리기 쉽고 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점이 존재 한다.

4. calculator 패키지 만들기

앞으로 개발하면서 많은 패키지를 사용할 것이고 만들어야 하는 경우도 있을 수 있기 때문에 이번과제는 직접 패키지를 만들어 보는 과제 입니다.

로컬 환경에서 파이썬을 설치하고 진행해 주세요.

디렉토리 구조는 다음과 같고 각 파일의 코드내용은 다음과 같습니다.
init.py 파일에는 아무코드도 없지만 init 파일은 해당 디렉토리가 패키지임을 알려주는 역할을 합니다.

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.py

multiplication.py

  1. main.py에서 상대경로로 add_and_mutiply 를 임포트 했을 때 발생하는 에러를 확인하고
    다음의 파이썬 공식 문서를 참고해서 main module 에서는 패키지의 모듈을 어떻게 임포트 해야하는지 블로깅 해주세요.
    https://docs.python.org/3/tutorial/modules.html#intra-package-references

    다음과 같은 에러가 나타난다.

    ImportError: attempted relative import with no known parent package

    해당 에러는 상대 경로로 import 했을 때 main.py 와 add_and_multiply와 상대적으로 경로를 받고 있지 않다는 이야기다.

    [main.py]

    [output]

    따라서 main.py를 절대경로(absolute path)로 수정하면 결과는 5가 나온다.

    현재 디렉토리를 기준으로 찾아갈 파일의 상대적인 경로를 찾아야 하는게 realative path 이다.
    그렇기 때문에 main.module이 import 할 다른 package안에 속해 있지 않을 때는 절대경로를 통해 모듈이나 패키지를 import 해줘야 한다.

  1. add_and_multiply.py에서 multiply함수를 절대경로와 상대경로도 각각 임포트 해보고 main 모듈과 차이점을 생각해보고 결과를 출력해 보세요.
  • 절대 경로 import:

    실행이 가능하다.

  • 상대 경로 import:

    실행 오류

    ImportError: attempted relative import with no known parent package

  • add_and_multiply.py는 calculator 패키지의 모듈이다.

  • main.py는 add_and_multiply.py 모듈에 있는 함수를 받아 실행하는 모듈이다.

  1. __init__.py 파일의 역할에 대해서도 정리해서 블로깅 해주세요.
  • package가 import 될때 초기 설정으로 __init__.py 파일을 만든다.

  • Package 안에 __init__.py 파일이 있으면 package가 import 될때 __init__.py 파일의 코드들이 자동으로 실행된다.

1. Import 할때 경로의 총 길이를 줄여준다.

import pkg.mod1

pkg.mod1.func2()
  • 매번 모든 경로를 다 타입해줘야 함.
  • __init__.py 파일을 통해 함수의 경로를 줄여줄 수 있다.
  • __init__.py 파일에 먼저 한번 import 해주면 된다.
#__init__.py
from .mod1 import func2

#main.py
from pkg import func2

func2()

2. Package에서 import 할 수 있는 변수/함수/클래스 제한하기

__init.py__ 파일을 사용해서 import 할 수 있는 변수/함수/클래스를 제한할 수 있다.
__all__ 변수를 지정: 외부에 노출되면 안 되는 함수가 package 외부에서 import되어 사용되는 것을 막기 위해서 사용

__all__ 변수는 string 값의 요소를 가지고 있는 list다 (list of strings).
그러므로 import 되길 원하는 요소들을 string으로 list에 선언해주면 된다.

#__init__.py
from .mod1 import func2
from .mod2 import func3

__all__ = ['func2', 'func3']
#main.py
from pkg import *

func2()
func3()
func4() ## <== Error. func4 함수는 __all__ 에 정의되지 않았으므로 import 될 수 없음.

3. 그 외 package가 import될때 꼭 먼저 실행되어야 하는 코드들을 실행해준다.

profile
꾸준히!

0개의 댓글