[wecode 8일차] - Modules

hyuckhoon.ko·2020년 6월 1일
0

What I learned in wecode

목록 보기
38/109

1. 모듈

1) 모듈이란?

변수, 함수 그리고 객체 등을 모아둔 파이썬 파일(.py)을 의미한다.

2) 모듈 사용 방법

(1) import

import 모듈이름 또는 import 패키지 이름

예) my_module.py라는 모듈일 경우, 
import my_module

my_module.my_func()

<모듈 이름>.<모듈에서 사용하길 원하는 변수/함수/클래스 이름> 과 같이 dot(점)을 활용하여 모듈의 메소드에 접근한다.

(2) from과 import

from 모듈이름 import 변수/함수/객체

import라는 간단한 방법이 있는데,
왜 'from, import'방식이 또 있는걸까?

아래 코드를 보고 어떤 편리함을 가져다 주는지 알아보자.

from my_module import my_module_func, my_module_var

print(my_module_var)
my_module_func()

이점 : 모듈이름을 작성하지 않고 바로 함수나 변수 사용이 가능하다.

(3) import ~ as ~

    import my_module as m

    m.my_func()
    print(m.my_variable)

모듈이름이 너무 길거나(가독성 떨어짐)
서로 다른 모듈에서 불러온 함수의 이름이 동일할 수도 있다.
이럴 때 모듈의 이름을 바꿔주어 이름충돌을 피한다.

2. 패키지

Package

1. 패키지란?

파이썬 파일(.py)들이 모인 집합을 패키지라고 한다.

2. 패키지 사용법

Package는 일반 모듈 처럼 import 하여 사용한다.
단, package의 원하는 모듈을 .(점)을 통해 import 한다..

# pkg의 mod1.py모듈 접근
import pkg.mod1

# pk1의 mod2.py모듈에서 func2를 import
from pkg.mod2 import func2


# pkg의 mod1.py모듈 안에 있는 func2 함수를 사용
pkg.mod1.func2()

func2()

3. 패키지 초기화

Package가 import 될 때 초기 설정을 해줘야 할 때가 있다.

Package 안에 init.py 파일이 있으면
package가 import 될때 init.py 가 자동으로 실행된다.

3. 과제

1. 차이점 : sys.modules 과 sys.path

1. sys.modules

이미 import된 모듈이나 패키지들의 디렉토리(폴더)를 의미한다.
차이점
1) 파이썬 프로그램을 실행시킬 때, 가장 먼저 sys.modules 디렉토리 검색
2) 딕셔너리 자료구조로 모듈 경로들이 입력되어 있다.

import sys
print(sys.modules)

결과
{'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>, '_frozen_importlib': <module '_frozen_importlib' (frozen)>, '_imp': <module '_imp' (built-in)>, '_warnings': <module '_warnings' (built-in)>, '_frozen_importlib_external': <module '_frozen_importlib_external' (frozen)>, '_io': <module 'io' (built-in)>, 'marshal': <module 'marshal' (built-in)>, 'posix': <module 'posix' (built-in)>, '_thread': <module '_thread' (built-in)>, '_weakref': <module '_weakref' (built-in)>, 'time': <module 'time' (built-in)>, 'zipimport': <module 'zipimport' (frozen)>, '_codecs': <module '_codecs' (built-in)>, 'codecs': <module 'codecs' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/codecs.py'>, 'encodings.aliases': <module 'encodings.aliases' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/encodings/aliases.py'>, 'encodings': <module 'encodings' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/encodings/init.py'>, 'encodings.utf_8': <module 'encodings.utf_8' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/encodings/utf_8.py'>, '_signal': <module '_signal' (built-in)>, 'main': <module 'main' from '/Users/khh180cm/Documents/python_project/module/module.py'>, 'encodings.latin_1': <module 'encodings.latin_1' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/encodings/latin_1.py'>, '_abc': <module '_abc' (built-in)>, 'abc': <module 'abc' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/abc.py'>, 'io': <module 'io' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/io.py'>, '_stat': <module '_stat' (built-in)>, 'stat': <module 'stat' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/stat.py'>, '_collections_abc': <module '_collections_abc' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/_collections_abc.py'>, 'genericpath': <module 'genericpath' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/genericpath.py'>, 'posixpath': <module 'posixpath' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/posixpath.py'>, 'os.path': <module 'posixpath' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/posixpath.py'>, 'os': <module 'os' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/os.py'>, '_sitebuiltins': <module '_sitebuiltins' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/_sitebuiltins.py'>, 'site': <module 'site' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site.py'>}



2. sys.path

차이점 :
1) 구조는 각 요소가 문자열 형태로 구성된 리스트다.
각 요소는 모듈이 있는 경로를 표시하고 있다.
2) 검색 순서sys.modules -> built-in modules 다음

import sys
print(sys.path)

결과
['/Users/khh180cm/Documents/python_project/module', '/Library/Frameworks/Python.framework/Versions/3.8/lib/python38.zip', '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8', '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages']



2. 파이썬의 sys모듈의 위치 찾는법

sys 모듈은 파이썬이 설치될 때 함께 설치되는 라이브러리 모듈이다.

import sys
print(sys.modules)

아래와 같이 sys': <module 'sys' (built-in)
built-in modules 에서 sys 모듈을 찾고있다는 걸 알 수 있다.

{'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>, '_frozen_importlib': <module '_frozen_importlib' (frozen)>, '_imp': <module '_imp' (built-in)>, '_warnings': <module '_warnings' (built-in)>, '_frozen_importlib_external': <module '_frozen_importlib_external' (frozen)>, '_io': <module 'io' (built-in)>, 'marshal': <module 'marshal' (built-in)>, 'posix': <module 'posix' (built-in)>, '_thread': <module '_thread' (built-in)>, '_weakref': <module '_weakref' (built-in)>, 'time': <module 'time' (built-in)>, 'zipimport': <module 'zipimport' (frozen)>, '_codecs': <module '_codecs' (built-in)>, 'codecs': <module 'codecs' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/codecs.py'>, 'encodings.aliases': <module 'encodings.aliases' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/encodings/aliases.py'>, 'encodings': <module 'encodings' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/encodings/init.py'>, 'encodings.utf_8': <module 'encodings.utf_8' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/encodings/utf_8.py'>, '_signal': <module '_signal' (built-in)>, 'main': <module 'main' from '/Users/khh180cm/Desktop/calculator/test.py'>, 'encodings.latin_1': <module 'encodings.latin_1' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/encodings/latin_1.py'>, '_abc': <module '_abc' (built-in)>, 'abc': <module 'abc' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/abc.py'>, 'io': <module 'io' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/io.py'>, '_stat': <module '_stat' (built-in)>, 'stat': <module 'stat' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/stat.py'>, '_collections_abc': <module '_collections_abc' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/_collections_abc.py'>, 'genericpath': <module 'genericpath' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/genericpath.py'>, 'posixpath': <module 'posixpath' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/posixpath.py'>, 'os.path': <module 'posixpath' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/posixpath.py'>, 'os': <module 'os' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/os.py'>, '_sitebuiltins': <module '_sitebuiltins' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/_sitebuiltins.py'>, 'site': <module 'site' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site.py'>}

3. 차이점 : Absolute path와 relative path

1) Absolute path

(1) 절대경로다.

(2) 절대경로는 현재 디렉토리부터 시작됨

(3) 단점 : 경로가 길어질 수 있음

2) Relative path

(1) 상대경로다.

(2) 현재 디렉리가 import된 위치가 시작점

ex) 동일 패키지에서 다른 함수를 사용하는 경우

from . import class1

(3) 단점 : 경로가 길어질 수 있음



4. calculator 패키지 만들기



5. main.py의 경로 지정 문제

Q. main.py에서 상대경로로 add_and_mutiply 를 임포트 했을 때 발생하는 에러를 확인하고 main module 에서는 패키지의 모듈을 어떻게 임포트 해야하는지 설명하시오.

에러 ImportError: attempted relative import with no known parent package

from .calculator.add_and_multiply import add_and_multiply

if __name__ == '__main__':
    print(add_and_multiply(1,2))
    print(__name__)
    print("ok")

상대경로로 모듈을 import하게 되면
시작기준점은 현재파일이 된다.
이것이 모든 문제를 야기시킨다.

(참고) 내가 작성한 파일(모듈)명이 main.py이든, test.py이든 practice.py이든 not_main.py이든

내가 실행(F5)시키는 바로 그 파일이 바로 __main__ 이다.
즉, __name__은 작동중인 모듈의 이름이 저장되는 변수에 불과하다.

따라서, 파이썬 인터프리터 입장에서는

"내가 지금 어디(어느 경로)에 있는지는 모르겠지만만

일단 지금 실행시키는 파일이 __main__이라고 하더라" 라고 인식하는 것이다.

따라서,

    if __name__ == '__main__': 

인 경우에는 절대경로를 지정해줘서 인터프리터가 다른 모듈 및 패키지를 참조할 수 있도록 해줘야 하는 것이다.


6. main.py 이외 파일의 경로지정 문제

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

절대경로

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(2,5))

main 모듈과 현재 add_and_multiply.py는 서로 연결되어 있지 않은 상태다.
add_and_multiply.py함수를 실행시키면 현재 이 파일이 __main__이 된다.
따라서, 메인모듈에서 진행했던 이전 예제와 마찬가지로
절대경로로 지정해줘야 한다.

(참고) 그렇다면 왜 아래와 같이 절대경로로 설정한 것 역시 에러가 출력될까

from calculator.multiplication import multiply

뭔가 문제다 싶으면 파일 경로를 자세히 봐야한다.

현제 내가 실행시키고 있는 파일은 add_and_multiply.py인데,
calculator 폴더 안에 multiplication.py도 함께 있다.
즉, 같은 폴더 안에서의 절대경로 지정하기 위해서는 그 다음 하위 모듈을
기준으로 경로를 작성해야 한다.


7. init.py의 역할

Q. __init__.py 파일의 역할

첫 번째 역할 : 파이썬 인터프리터가 경로를 탐색하도록 하게 한다.

예시

mydir/spam/__init__.py
mydir/spam/module.py

위와 같은 경로가 있다.
__ìnit__.py덕분에 파이썬은
mydir 디렉토리 안의 -> spam 디렉토리 안의 -> module.py까지 접근한다.

따라서

from spam import module

과 같은 방식으로 모듈을 import 할 수 있다.

두 번째 역할 :

  • Import 할때 경로의 총 길이 줄여주기
  • Package에서 import 할 수 있는 변수/함수/클래스 제한하기
  • 그 외 package가 import될때 꼭 먼저 실행되어야 하는 코드들

예시

# __init__.py
from .mod1 import func2
# main.py
from pkg import func2

func2()

__init__.py에서 경로 길이를 줄여주지 않았다면

import pkg.mod1

pkg.mod1.func2()

처럼 사용해야 한다.

0개의 댓글