본문 바로가기
언어/Python

[Python 기본 공부정리] 10. 패키지(package)

by 민-Zero 2020. 1. 4.

공부 내용을 정리하는 목적 이므로 참고용으로만 읽어 주시기 바랍니다.

틀린 부분에 대한 지적은 감사합니다.

1. 패키지(package)란?

모듈이 함수, 변수 클래스 또는 실행코드들을 논리적으로 하나로 묶어서 관리하고 사용할 수 있도록 텍스트 형식으로 만들어 놓은 파일이었다면 패키지는 이 모듈들을 묶어서 계층적 구조(디렉토리 구조)로 관리하는 것을 뜻한다. 여기서 디렉토리란 폴더를 말한다. 쉽게 말해 우리가 일상에서 학교에서 각 과목마다 폴더를 만들어 과목마다 해당하는 내용을 그 폴더에 넣고 또 해당 과목의 세부적인 사항을 폴더로 만들어 내부에 세부내용을 넣어 정리하는것 처럼 모듈을 관리하는 것이다.

연습하기 위해 간단하게 패키지를 생성해 보았다.

간단히 사용하기 위해 다음과 같은 디렉토리 구조를 생성했다.

Study(디렉토리) : study.py(모듈 사용을 위한 코드)

  ↘S_A(디렉토리) : __init__.py, s_a_mod.py(모듈)

    ↘S_B(디렉토리) : __init__.py, s_b_mod.py(모듈)

      ↘S_C(디렉토리) : __init__.py, s_c_mod.py(모듈)

각각 폴더를 생성하고 그 안에 .py 확장자의 파일들을 생성한 것이다. 

또한 각 모듈에 어떤 모듈의 함수가 호출되는지 확인하기 위해 간단한 출력 함수를 생성했다. 

 

2. 패키지 실행

패키지는 모듈을 계층적 구조로 관리하기 위한 것일 뿐 무언가 특별한 기술이 필요한 것이 아니다. 따라서 패키지의 모듈을 사용하는 것은 그냥 모듈을 사용하는 것처럼 import를 통해 사용하면 된다.

모듈들을 테스트하기 위한 study.py 에서 S_A 디렉토리에 있는 s_a_mod.py 를 불러와 해당 모듈의 함수를 실행한 모습이다. 현재 디렉토리의 하위 디렉토리에 존재하므로 import시 (.) 도트 연산자를 통해 경로를 알려주어 모듈을 불러오고 그다음 해당 모듈이 가진 함수등을 사용할 수 있게 된다. 이제 하위에 하위로 내려가게 되면 . 를 통해 많은걸 입력해야 하므로 import from 구문을 잘 활용해야 한다.

from에 어떤 디렉토리에 있는 어떤 모듈인지 알려주고 import에 어떤 함수를 사용할 것인지 알려주면 (.)을통해 길게 작성하지 않아도 된다.

 

S_C에 있는 모듈을 사용해보면

from S_A.S_B.S_C.s_c_mod import s_c_test → "S_A 안에 S_B 안에 S_C 안에 s_c_mod라는 모듈에 s_c_test라는 함수를 불러오자"라고 해석하면 이해하기 편하다.

 

3. __init__.py

class에선 __init__함수가 생성자로 쓰였지만 패키지에서 __init__.py는 단순히 해당 디렉토리가 패키지의 일부임을 알려주는 역할이다. python 3.3 버전 부터는 __init__.py 파일이 없어도 패키지로 인식하여 3.3이상의 버전을 사용한다면 따로 만들지 않아도 패키지로 동작하지만 3.3미만 버전은 __init__.py 파일이 없다면 패키지로 인식하지 않기 때문에 하위 버전과의 호환성을 위해 __init__.py 파일을 생성하는 것이 안전하다.

 

또한 __init__.py를 이용하여 한 가지 문제를 해결할 수 있다.

패키지에서 *(모든 것)을 import 하면 s_c_mod 모듈을 사용할 수 있어야 하는데 s_c_mod라는 이름이 정의되지 않았다는 에러가 발생한다. 이를 해결하기 위해서는 S_C 디렉토리의 __init__.py 에 __all__ 변수에 값을 추가해야 한다.

S_C의 __init__.py

 

그러면 *을 사용하여 모듈을 import 할 수 있다.

__all__이 의미하는 것은 S_C 디렉토리에서 * 기호를 사용하여 import 할 경우 해당 디렉토리에 정의된 echo 모듈만 import 된다는 의미이다. 만약 다른 모듈이 더 있을 경우 __all__ 가 가진 리스트에 모듈을 더 추가해야 한다.

헷갈리면 안 되는 점은 from 부분이 디렉토리로만 이루어진 경우 import에 * 를 사용하기 위한 방법이다. 

from S_A.S_B.S_C.s_c_mod 로 마지막에 모듈까지 작성한 경우 __init__ 에 아무것도 추가하지 않아도 *를 사용할 수 있다.

 

4. 상대(relative) 경로, 절대(absolute) 경로

리눅스 OS 등을 사용해 봤다면 상대(relative) 경로, 절대(absolute) 경로가 굉장히 익숙할 것이다. 이 경로를 import from에 디렉토리 경로를 이용할 때 사용 가능하다.

 

각 경로를 간단히 설명하면,

절대 경로 - 사용자가 사용할 때 사용하고자 하는 파일 또는 웹페이지 등 경로가 필요한 모든 것에 대해 최초 시작점을 기준으로 하는 고유한 모든 경로

상대 경로 - 사용자가 사용할때 사용하고자 하는 파일또는 웹페이지등 경로가 필요한 모든것에 대해 현재 위치한 곳을 기준으로 하는 그곳의 위치에 대한 경로

헷갈릴 수 있지만 차이점은 기준점이 어디인가 이다. 절대 경로는 최초 시작점이 기준이고 상대 경로는 현재 위치가 기준이 된다.

 

S_C 디렉토리에 s_c_confirm.py라는 실행 파일을 만들어 해당 파일에서 S_B에 있는 모듈을 사용한다고 가정하자. 

Study(디렉토리) : study.py(모듈 사용을 위한 코드)

  ↘S_A(디렉토리) : __init__.py, s_a_mod.py(모듈)

    ↘S_B(디렉토리) : __init__.py, s_b_mod.py(모듈)

      ↘S_C(디렉토리) : __init__.py, s_c_mod.py(모듈), s_c_confirm.py

즉, S_C 디렉토리 위치에서 기능을 수행하기 위해 다음과 같이 파일을 하나 추가한 것뿐이다.

 

절대 경로를 사용한다면 s_b_mod 모듈이 존재하는 패키지 시작 위치인 S_A부터 전부 적어 주면 된다. 계속 써왔던 일반적인 경로이다. 

상대 경로는 해당 파일이 존재하는 위치를 기준으로 시작점이 결정된다. 

다음과 같은 경로를 사용한다. 여기서 (..)은 현재 위치의 상위 디렉토리를 의미 한다. 따라서 현재 디렉토리 위치인 S_C의 상위 디렉터리 S_B의 s_b_mod에서 s_b_test라는 함수를 불러온 것이다.

relative 경로에서 (..)은 상위 디렉토리, (.)은 현재 디렉토리를 뜻한다.

댓글