파알못 파이썬: 5. 모듈

Table of Content

파이썬을 공부한 내용을 정리한 글입니다. 파알못이라 이상하거나 틀린 내용이 있을 수 있습니다…

모듈

지금까지 모든 코드를 하나의 파일로 작성했습니다. 코드를 모듈화하여 여러 소스코드 파일로 분리하여 저장할 수 있습니다.

함수를 2개 갖는 모듈을 간단히 만들어보겠습니다.

  • sales.py
def calc_tax():
    pass

def calc_shipping():
    pass

위에서 만든 모듈을 가져오려면 from 모듈명 import 가져올_객체명 코드를 추가합니다. 이 때 import * 코드를 사용하면 모듈 내에 있는 모든 변수 및 함수 등을 맹목적으로 가져오지만 다른 모듈에서 같은 이름의 변수 또는 함수를 가져올 때 충돌이 발생할 수 있으므로 필요한 부분만 import 하는 것이 좋습니다.

  • app.py
from sales import calc_shipping, calc_tax
# from sales import * # 모듈 내 모든 변수 및 함수 등을 가져옴

# import한 함수 호출
calc_shipping()
calc_tax()

모듈 전체를 import 하려는 경우 import 모듈명 코드를 사용할 수 있습니다. 이 방법은 위의 방법과 달리 이름이 같은 변수 또는 함수와 충돌이 발생하지 않습니다. 변수나 함수를 호출할 때 모듈명 뒤에 점(.)을 붙여 접근합니다.

  • app.py
import sales  # sales 모듈 import

# import한 함수 호출
sales.calc_shipping()
sales.calc_tax()

from ~ import 코드를 사용할지 import ~ 코드를 사용할지는 개발자의 취향(?)입니다. 존중입니다. 취향해주시죠.

컴파일된 파이썬 파일

파이썬 코드를 작성한 후 컴파일을 시도하면 __pycache__ 폴더가 생성되고 이 안에 컴파일된 파이썬 바이트 코드 파일이 생성됩니다. 다음에 파이썬 프로그램을 실행하면 파이썬은 이 폴더에 컴파일된 파일이 있으면 컴파일을 생략하고 바로 실행합니다. 컴파일 단계를 뛰어넘으면 실행속도가 더 빨라질 겁니다. 실제 성능은 그대로겠지만요.

그렇다면 이 컴파일된 파이썬 파일이 최신버전인지 파이썬은 어떻게 알 수 있을까요? 기본적으로 소스코드 파일과 컴파일된 파이썬 파일이 생성된 시간을 비교합니다. 소스코드 파일이 더 최신인 경우 소스코드가 변경되었다는 것을 인식하고 다시 컴파일합니다.

모듈 검색 경로

import sales 코드를 통해 파이썬은 현재 디렉토리에 위치한 sales.py 파일을 찾습니다. 이 파일을 찾지 못하면 파이썬 설치 시에 제공된 모듈 디렉토리를 검색합니다.

import sales
import sys

print(sys.path)

패키지(Package)

위에서 만든 모듈은 메인 모듈과 같은 경로에 위치합니다. 그런데 모듈 모들을 같은 경로에 두면 매우 복잡해집니다. 서로 연관성이 있는 모듈들을 한 데 모아 관리하면 좀 더 편해집니다.

파이썬에선 디렉토리를 만들어 그 안에 여러 모듈을 담을 수 있습니다. 이 디렉토리를 패키지라고 부릅니다. 아래 예제는 위에서 만든 sales 모듈을 ecommerce 패키지에 포함시키는 예제입니다.

  1. 메인 모듈(app.py)이 위치한 곳에 ecommerce라는 디렉토리를 만든 후 이 안에 sales.py 파일을 이동시킵니다.
  • ./ecommerce/sales.py
def calc_tax():
    pass

def calc_shipping():
    pass
  1. ecommerce 디렉토리 안에 __init__.py 파일을 만듭니다. 이 파일은 해당 디렉토리가 파이썬 패키지임을 명시합니다.
  • ./ecommerce/__init__.py
# 빈 파일
  1. 메인 모듈(app.py)에서 이 패키지와 모듈을 import 합니다.
  • app.py
import ecommerce.sales

ecommerce.sales.calc_tax()
  1. 위의 import ~ 방법은 점(.) 연산이 반복되어 코드가 길어집니다. 이 방법을 대신하려면 from ~ import ~ 코드를 사용합니다.
  • app.py
from ecommerce.sales import calc_tax

calc_tax()
  1. 물론 위의 방법도 import할 객체가 많아지면 코드가 길어지게 됩니다. 3번을 택할지 4번을 택할지는 개발자의 취향(?)입니다. 존중입니다. 취향해주시죠.

서브패키지(Sub-Packages)

프로그램이 복잡해짐에 따라 패키지를 계층별로 세분화할 수 있습니다. 이를 위해 패키지 디렉토리 내에 디렉토리를 만들어 서브 패키지를 만들 수 있습니다.

  1. 메인 모듈(app.py)이 위치한 곳에 ecommerce라는 디렉토리를 만들고 이 안에 shopping이라는 디렉토리를 만든 후 이 안에 sales.py 파일을 이동시킵니다.
  • ./ecommerce/shopping/sales.py
def calc_tax():
    pass

def calc_shipping():
    pass
  1. shopping 디렉토리 안에 __init__.py 파일을 만듭니다. 이 파일은 해당 디렉토리가 파이썬 패키지임을 명시합니다.
  • ./ecommerce/__init__.py
# 빈 파일
  1. 메인 모듈(app.py)에서 이 서브패키지 모듈을 import 합니다.
  • app.py
import ecommerce.shopping.sales

ecommerce.shopping.sales.calc_tax()

또는

from ecommerce.shopping.sales import calc_tax

calc_tax()

패키지 내 참조

형제 패키지(같은 패키지에 포함된 서브패키지)에서 모듈을 가져오려는 경우가 있을 수 있습니다. 예를 들어 다음과 같이 ecommerce 패키지에 customer 패키지와 shopping 패키지가 있다고 가정해봅시다.

  • ./app.py: 메인 모듈
  • ./ecommerce: 패키지(ecommerce)
  • ./ecommerce/customer: 서브패키지(customer)
  • ./ecommerce/customer/contact.py: 서브패키지(customer)의 모듈(contact)
  • ./ecommerce/shopping: 서브패키지(shopping)
  • ./ecommerce/shopping/sales.py: 서브패키지(shopping)의 모듈(shopping)

shopping 패키지에서 customer 패키지에 포함된 모듈을 가져오려면 어떻게 해야 할까요? 이 때도 마찬가지로 from, import 코드를 사용하여 형제 패키지 모듈을 가져오면 됩니다.

이 때 패키지 경로를 절대경로와 상대경롤 지정할 수 있습니다. 가장 좋은 방법은 PEP 8에 정의된 절대경로를 사용하는 것입니다. 그러나 절대경로로 코딩하기에 너무 장황한 경우 상대경로를 사용할 수 있습니다.

  • ./ecommerce/shopping/sales.py
from ecommerce.customer import contact  # 절대경로
from ..customer import contact # 상대경로(.: 현재 위치, ..: 이전 위치)

contact.contact_customer()

def calc_tax():
    pass

def calc_shipping():
    pass

dir() 내장함수

dir() 내장함수를 사용하면 정의된 속성 및 메소드 목록울 얻을 수 있습니다.

  • app.py
from ecommerce.shopping import sales

print(dir(sales))

위 코드를 실행하면 ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'calc_shipping', 'calc_tax', 'contact'] 라는 결과가 나옵니다.

  • __name__: 모듈의 이름
  • __package__: 패키지의 이름
  • __file__ 모듈이 정의된 소스코드의 파일 이름 및

main 모듈

프로그램을 시작하는 모듈의 이름은 main 모듈입니다.

  • app.py
from ecommerce.shopping import sales

print("App initialized:", __name__)
sales.calc_tax()
  • ./ecommerce/shopping/sales.py
def calc_tax():
    pass

def calc_shipping():
    pass

print("Sales initialized:", __name__)

다음과 같이 main 모듈에서 실행되었을 때와 다른 모듈에서 호출되었을 때의 작동을 구분할 수 있습니다..

  • ./ecommerce/shopping/sales.py
print("Sales initialized:", __name__)

if __name__ == "__main__":
    print("Sales started")
    # main 모듈에서 실행되었을 때의 작동 코드
    # 이 블록은 다른 모듈에서는 실행되지 않음

def calc_tax():
    pass

def calc_shipping():
    pass

댓글 남기기