About Python – “패키지 – Packages”

About Python – “패키지 – Packages”

1월 31, 2022

파이썬의 패키지 (Packages)

Python has only one type of module object, and all modules are of this type, regardless of whether the module is implemented in Python, C, or something else. To help organize modules and provide a naming hierarchy, Python has a concept of packages.

You can think of packages as the directories on a file system and modules as files within directories, but don’t take this analogy too literally since packages and modules need not originate from the file system. For the purposes of this documentation, we’ll use this convenient analogy of directories and files. Like file system directories, packages are organized hierarchically, and packages may themselves contain subpackages, as well as regular modules.

파이썬은 한 가지 종류의 모듈 객체만 갖고 있고, 모든 모듈은 모듈이 파이썬이나 C나 그 밖의 다른 어떤 방법으로 구현되었는지와 상관없이 이 형입니다. 모듈을 조직화하고 이름 계층구조를 제공하기 위해, 파이썬은 패키지 라는 개념을 갖고 있습니다.

패키지를 파일 시스템에 있는 디렉터리라고 생각할 수 있지만, 패키지와 모듈이 파일시스템으로부터 올 필요는 없으므로 이 비유를 너무 문자 그대로 해석하지 말아야 합니다. 이 문서의 목적상, 디렉터리와 파일이라는 비유를 사용할 것입니다. 파일 시스템 디렉터리처럼, 패키지는 계층적으로 조직화하고, 패키지는 보통 모듈뿐만 아니라 서브 패키지도 포함할 수 있습니다.

모든 패키지가 모듈이라는 것을 기억하는 것이 중요합니다. 하지만 모든 모듈이 패키지인 것은 아닙니다. 다른 식으로 표현하면, 패키지는 특별한 종류의 모듈입니다. 구체적으로, __path__ 어트리뷰트를 포함하는 모든 모듈은 패키지로 취급됩니다.

출처 : 파이썬 공식 문서

파이썬 공식 문서에서는 “.‘ 을 이용하여 모듈을 부모 패키지와 서브 패키지로 관리할 수 있게끔 해 준다고 소개하고 있습니다.

실습으로 파이썬의 패키지 알아보기

파이참에서 패키지 만들기.

파이참에서 다음과 같이 우클릭을 하여 패키지를 만들 수 있습니다. 파이참이 아닌 다른 도구를 사용하더라도 관계는 없습니다. 위와 같이 패키지를 만들면 자동으로 디렉터리와 함께, __init__.py 파일이 만들어집니다. 생성된 __init__.py의 내용은 아무것도 적혀 있지 않습니다. 다른 도구를 이용하는 분들은, __init__.py 파일을 같은 디렉토리에 생성만 해 둡시다.

최종 패키지의 모습.

패키지를 만드는 과정을 반복하여 위와 같은 구조의 패키지를 만들어 봅시다. 각각 파일의 코드는 아래와 같습니다.

languages_list = ["영어", "한국어"]

def printLlist():
    print(languages_list)
english_hello = "Hello, nice to meet you."
korean_hello = "안녕하세요, 만나서 반갑습니다."

def  sayHello_English():
    print(english_hello)

def sayHello_Korean():
    print(korean_hello)

실습으로 만든 파이썬 패키지 사용해 보기

set PYTHONPATH = (패키지가 있는 디렉토리)

위의 명령어를 터미널에서 실행해 줍니다.

새로 test.py 파일을 생성해 줍니다.

test.py를 만들어 주고 아래와 같이 내용을 입력 해 봅니다.

# 방법 1 : 패키지에 있는 모듈을 임포트해서 사용하기
import SayHello.languages.languagesList
import SayHello.printHello.sayHello

SayHello.languages.languagesList.printLlist()
SayHello.printHello.sayHello.sayHello_English()

위와 같이, import를 사용하여 패키지에 있는 모듈을 사용하는 방법이 있습니다.

# 방법 2 : from, import 를 이용하여 사용하기
from SayHello.languages.languagesList import *
from SayHello.printHello.sayHello import *

printLlist()
sayHello_English()

또, 위처럼 import ~ from을 사용할 수도 있습니다.

# 더 하위 디렉토리의 모듈을 사용할 수는 없다.
import SayHello

SayHello.languages.languagesList.printLlist()
# AttributeError: module 'SayHello' has no attribute 'languages'

SayHello 패키지가 모든 모듈들을 포함하고 있으므로 SayHello import 해서 사용할 수 있지 않을까? 하여 위와 같은 코드를 작성하면 에러가 납니다. 해당 디렉터리에 있는 모듈이나 __init__.py 만 참조할 수 있음을 기억하고, 사용하고자 하는 모듈이나 패키지의 디렉터리 구조를 정확히 작성하는 것을 기억하는 것이 좋겠습니다.

파이썬의 패키지에서 __init__.py 란?

Note that an ImportWarning will no longer be raised for a directory lacking an __init__.py file. Such a directory will now be imported as a namespace package, whereas in prior Python versions an ImportWarning would be raised.

ImportWarning은 __init__.py 파일이 없는 디렉토리에 대해 더 이상 발생하지 않습니다. 이러한 디렉토리는 이제 네임스페이스 패키지로 가져오는 반면 이전 Python 버전에서는 ImportWarning이 발생했습니다.

https://www.python.org/dev/peps/pep-0420/

__init__.py는 해당 파일이 있는 디렉토리가 패키지의 일부임을 알려주는 역할을 했지만, 위의 문서를 보면 알 수 있듯이 3.3 버전부터는 ImportWarning이 발생하지 않는다고 합니다.

# 1번 경우
from SayHello.printHello import *
# SayHello.printHello 디렉토리의 모든 모든 것을 import해라!
sayHello.sayHello_English()


# 2번 경우
from SayHello.printHello.sayHello import *
# SayHello.printHello.SayHello 모듈의 모든 것을 import해라!
sayHello_English()

먼저 위의 코드에서 1번 경우를 살펴봅시다. from SayHello.printHello import *printHello 디렉토리의 모든 것을 import 하라는 코드가 작성되어 있습니다. 하지만 printHello 안의 sayHello 모듈을 사용하면 오류가 납니다.

2번의 경우는 from SayHello.printHello.sayHello import *printHello 디렉토리의 sayHello 모듈의 모든 것을 import 하라는 코드가 작성되어 있습니다. 모듈 자체의 모든 것을 import 하라고 했으므로 2번의 경우에는 오류가 나지 않습니다.

그렇다면 1번과 2번의 차이는 “모듈이 포함되어 있는 디렉토리의 모든 것을 import해라” 와 “어떤어떤 모듈의 모든 것을 import해라” 가 됩니다. 모듈이 포함된 디렉토리를 import 할 때에는 해당 디렉토리의 __init__.py에 이 “디렉토리에서 import할 수 있는 모듈은 이것이다.” 라고 말해주어야 하는데, 그 작업을 해 보겠습니다.

어떤 디렉토리의 모듈을 모두(*를 사용하여) import 할 경우, 그 디렉토리의 __init__.py__all__ 변수를 설정해 주어야 합니다.

__all__ = ["sayHello"]

우리는 printHello 디렉토리의 모든 것을 import하려고 하므로 printHello 디렉토리의 __init__.py에 위와 같은 코드를 추가합니다. __all__ 변수의 타입을 출력해 보면 <class 'list'> 와 같이 리스트 자료형이라는 것을 알려주고 있습니다. 만약 해당 디렉토리에 import * 로 추가하고 싶은 모듈들이 더 있다면, 그것을 추가해 주면 됩니다.

# 1번 경우
from SayHello.printHello import *
# SayHello.printHello 디렉토리의 모든 모든 것을 import해라!
sayHello.sayHello_English()

위의 작업을 완료한 후 위의 코드를 실행해 보면 정상적으로 작동하는 것을 알 수 있습니다.

파이썬의 relative import

printHello 디렉토리 아래에 sayBye.py 모듈을 하나 더 만들어 보겠습니다.
from SayHello.printHello.sayHello import *
# from ..printHello.sayHello import *
kor_bye = "잘 가!"
eng_bye = "goodbye!"

if __name__ =='__main__':
    sayHello_English()

sayBye.py 파일을 위와 같이 수정해 봅시다. 맨 윗줄을 보면 sayHello 모듈의 모든 것을 import 하였으므로 sayHello_English() 함수를 사용할 수 있는 것을 확인할 수 있죠.

이제는 맨 윗줄의 코드를 주석 처리하고, 2줄의 코드를 주석 해제한 후 실행해 봅시다.

ImportError: attempted relative import with no known parent package 라는 오류가 발생할 것입니다. 그런데 그 코드를 그대로 놔 두고, test.py에 다음과 같은 코드를 입력하면 잘 실행됩니다.

분명히 sayBye 모듈을 그대로 실행하면 오류가 났었는데 그것을 import한 코드를 실행하면 오류가 납니다. relative import는 모듈로서만 사용되어야 합니다.

Leave A Comment

Avada Programmer

Hello! We are a group of skilled developers and programmers.

Hello! We are a group of skilled developers and programmers.

We have experience in working with different platforms, systems, and devices to create products that are compatible and accessible.