모듈 기본 사항 복습

Beginner

This tutorial is from open-source community. Access the source code

소개

이 랩에서는 Python 모듈의 기본 사항을 배우게 됩니다. 모듈은 다른 Python 프로그램에서 사용할 수 있는 함수, 클래스 및 변수 정의가 포함된 Python 파일입니다. 모듈은 코드를 논리적인 단위로 구성하고 재사용성을 향상시키는 데 도움이 됩니다.

이 랩을 마치면 자신만의 모듈을 만들고 다양한 방식으로 가져오는 방법과 코드에 영향을 미치는 중요한 모듈 로딩 동작을 이해하게 됩니다.

간단한 모듈 만들기

간단한 모듈을 만들어 Python 모듈 여정을 시작해 보겠습니다. Python 에서 모듈은 본질적으로 Python 코드를 담고 있는 .py 확장자를 가진 파일입니다. 관련 함수, 클래스 및 변수를 함께 그룹화할 수 있는 컨테이너라고 생각하십시오. 이렇게 하면 특히 프로젝트 규모가 커짐에 따라 코드를 더 체계적으로 관리하기가 쉬워집니다.

  1. 먼저 WebIDE 를 엽니다. 열리면 새 파일을 만들어야 합니다. 이렇게 하려면 메뉴 모음에서 "File"을 클릭한 다음 "New File"을 선택합니다. 이 새 파일의 이름을 simplemod.py로 지정하고 /home/labex/project 디렉토리에 저장합니다. 이 디렉토리는 이 실험과 관련된 모든 파일을 보관할 곳입니다.

  2. 이제 새로 만든 simplemod.py 파일에 코드를 추가해 보겠습니다. 아래 코드는 Python 모듈에서 일반적으로 발견되는 몇 가지 기본 요소를 정의합니다.

## simplemod.py

x = 42        ## A global variable

## A simple function
def foo():
    print('x is', x)

## A simple class
class Spam:
    def yow(self):
        print('Yow!')

## A scripting statement
print('Loaded simplemod')

이 코드에서:

  • x = 42x라는 전역 변수를 생성하고 값 42를 할당합니다. 전역 변수는 모듈 내 어디에서나 액세스할 수 있습니다.
  • foo() 함수는 전역 변수 x의 값을 출력하도록 정의됩니다. 함수는 특정 작업을 수행하는 재사용 가능한 코드 블록입니다.
  • Spam 클래스는 객체를 생성하기 위한 청사진입니다. yow()라는 메서드가 있으며, 이 메서드는 단순히 문자열 'Yow!'를 출력합니다. 메서드는 클래스에 속하는 함수입니다.
  • print('Loaded simplemod') 문은 스크립팅 문입니다. 모듈이 로드되는 즉시 실행되어 모듈이 성공적으로 로드되었는지 확인하는 데 도움이 됩니다.
  1. 코드를 추가한 후 파일을 저장합니다. 키보드에서 Ctrl+S를 누르거나 메뉴에서 "File" > "Save"를 선택하여 이 작업을 수행할 수 있습니다. 파일을 저장하면 변경한 모든 내용이 유지됩니다.

이 모듈에 포함된 내용을 자세히 살펴보겠습니다.

  • 42를 가진 전역 변수 x. 이 변수는 모듈 전체에서 사용할 수 있으며, 올바르게 가져온 경우 다른 모듈에서도 액세스할 수 있습니다.
  • x의 값을 출력하는 함수 foo(). 함수는 동일한 코드를 여러 번 작성하지 않고 반복적인 작업을 수행하는 데 유용합니다.
  • 메서드 yow()가 있는 클래스 Spam. 클래스와 메서드는 객체 지향 프로그래밍의 기본 개념으로, 복잡한 데이터 구조와 동작을 만들 수 있습니다.
  • 모듈이 로드될 때 실행되는 print 문. 이 문은 모듈이 Python 환경에 성공적으로 로드되었음을 시각적으로 나타내는 지표 역할을 합니다.

맨 아래의 print 문은 모듈이 로드될 때 관찰하는 데 도움이 되며, 이는 디버깅 및 Python 에서 모듈이 작동하는 방식을 이해하는 데 중요합니다.

모듈 가져오기 및 사용

이제 모듈을 만들었으므로, 이를 가져와서 구성 요소를 사용하는 방법을 이해할 차례입니다. Python 에서 모듈은 Python 정의와 문을 포함하는 파일입니다. 모듈을 가져오면 해당 모듈 내에 정의된 모든 함수, 클래스 및 변수에 액세스할 수 있습니다. 이를 통해 코드를 재사용하고 프로그램을 보다 효과적으로 구성할 수 있습니다.

  1. 먼저 WebIDE 에서 새 터미널을 열어야 합니다. 이 터미널은 Python 명령을 실행할 수 있는 작업 공간 역할을 합니다. 새 터미널을 열려면 "Terminal" > "New Terminal"을 클릭합니다.

  2. 터미널이 열리면 Python 인터프리터를 시작해야 합니다. Python 인터프리터는 Python 코드를 읽고 실행하는 프로그램입니다. 이를 시작하려면 터미널에 다음 명령을 입력하고 Enter 키를 누릅니다.

python3
  1. 이제 Python 인터프리터가 실행 중이므로 모듈을 가져올 수 있습니다. Python 에서는 import 문을 사용하여 현재 프로그램에 모듈을 가져옵니다. Python 인터프리터에 다음 명령을 입력합니다.
>>> import simplemod
Loaded simplemod

출력에 "Loaded simplemod"가 나타나는 것을 알 수 있습니다. 이는 simplemod 모듈의 print 문이 모듈이 로드될 때 실행되기 때문입니다. Python 은 모듈을 가져올 때 해당 모듈의 모든 최상위 코드를 실행하며, 여기에는 모든 print 문이 포함됩니다.

  1. 모듈을 가져온 후에는 점 표기법을 사용하여 해당 구성 요소에 액세스할 수 있습니다. 점 표기법은 Python 에서 객체의 속성 (변수 및 함수) 에 액세스하는 방법입니다. 이 경우 모듈은 객체이고 해당 함수, 변수 및 클래스는 속성입니다. simplemod 모듈의 다양한 구성 요소에 액세스하는 방법의 몇 가지 예는 다음과 같습니다.
>>> simplemod.x
42
>>> simplemod.foo()
x is 42
>>> spam_instance = simplemod.Spam()
>>> spam_instance.yow()
Yow!

첫 번째 줄에서는 simplemod 모듈에 정의된 변수 x에 액세스합니다. 두 번째 줄에서는 simplemod 모듈에서 함수 foo를 호출합니다. 세 번째 및 네 번째 줄에서는 simplemod 모듈에 정의된 Spam 클래스의 인스턴스를 생성하고 해당 메서드 yow를 호출합니다.

  1. 때로는 모듈을 가져오려고 할 때 ImportError가 발생할 수 있습니다. 이 오류는 Python 이 가져오려는 모듈을 찾을 수 없을 때 발생합니다. Python 이 모듈을 어디에서 찾고 있는지 확인하려면 sys.path 변수를 검사할 수 있습니다. sys.path 변수는 Python 이 모듈을 찾을 때 검색하는 디렉토리 목록입니다. Python 인터프리터에 다음 명령을 입력합니다.
>>> import sys
>>> sys.path
['', '/usr/lib/python310.zip', '/usr/lib/python3.10', '/usr/lib/python3.10/lib-dynload', '/usr/local/lib/python3.10/dist-packages', '/usr/lib/python3/dist-packages']

목록의 첫 번째 요소 (빈 문자열) 는 현재 작업 디렉토리를 나타냅니다. 이것이 Python 이 simplemod.py 파일을 찾는 곳입니다. 모듈이 sys.path에 나열된 디렉토리 중 하나에 없으면 Python 은 이를 찾을 수 없으며 ImportError가 발생합니다. simplemod.py 파일이 현재 작업 디렉토리 또는 sys.path의 다른 디렉토리 중 하나에 있는지 확인하십시오.

모듈 로딩 동작 이해

Python 에서 모듈이 로드되는 방식에는 몇 가지 흥미로운 특징이 있습니다. 이 단계에서는 Python 이 모듈 로딩을 관리하는 방식을 이해하기 위해 이러한 동작을 살펴보겠습니다.

  1. 먼저, 동일한 Python 인터프리터 세션 내에서 모듈을 다시 가져오려고 할 때 어떤 일이 발생하는지 살펴보겠습니다. Python 인터프리터를 시작하면 Python 코드를 실행할 수 있는 작업 공간을 여는 것과 같습니다. 모듈을 가져온 후 다시 가져오면 모듈이 다시 로드되는 것처럼 보일 수 있지만 그렇지 않습니다.
>>> import simplemod

이번에는 "Loaded simplemod" 출력이 표시되지 않는 것을 알 수 있습니다. 이는 Python 이 인터프리터 세션당 한 번만 모듈을 로드하기 때문입니다. 후속 import 문은 모듈을 다시 로드하지 않습니다. Python 은 이미 모듈을 로드했음을 기억하므로 다시 로드하는 과정을 거치지 않습니다.

  1. 모듈을 가져온 후에는 내부 변수를 수정할 수 있습니다. Python 의 모듈은 변수, 함수 및 클래스를 담는 컨테이너와 같습니다. 모듈을 가져오면 다른 Python 객체와 마찬가지로 해당 변수에 액세스하고 변경할 수 있습니다.
>>> simplemod.x
42
>>> simplemod.x = 13
>>> simplemod.x
13
>>> simplemod.foo()
x is 13

여기서는 먼저 simplemod 모듈의 변수 x의 값을 확인합니다. 초기 값은 42입니다. 그런 다음 값을 13으로 변경하고 변경 사항이 적용되었는지 확인합니다. 모듈에서 foo 함수를 호출하면 x의 새 값을 반영합니다.

  1. 모듈을 다시 가져와도 변수에 대한 변경 사항이 재설정되지 않습니다. 모듈을 다시 가져오려고 시도하더라도 Python 은 다시 로드하지 않으므로 변수에 대한 변경 사항이 유지됩니다.
>>> import simplemod
>>> simplemod.x
13
  1. 모듈을 강제로 다시 로드하려면 importlib.reload() 함수를 사용해야 합니다. 때로는 모듈의 코드를 변경하고 해당 변경 사항이 즉시 적용되는 것을 확인하고 싶을 수 있습니다. importlib.reload() 함수를 사용하면 그렇게 할 수 있습니다.
>>> import importlib
>>> importlib.reload(simplemod)
Loaded simplemod
<module 'simplemod' from 'simplemod.py'>
>>> simplemod.x
42
>>> simplemod.foo()
x is 42

모듈이 다시 로드되었고 x의 값이 42로 재설정되었습니다. 이는 모듈이 소스 코드에서 다시 로드되었고 모든 변수가 원래대로 초기화되었음을 보여줍니다.

  1. Python 은 sys.modules 딕셔너리에 로드된 모든 모듈을 추적합니다. 이 딕셔너리는 현재 인터프리터 세션 동안 로드된 모든 모듈에 대한 정보를 Python 이 저장하는 레지스트리 역할을 합니다.
>>> 'simplemod' in sys.modules
True
>>> sys.modules['simplemod']
<module 'simplemod' from 'simplemod.py'>

모듈 이름이 sys.modules 딕셔너리에 있는지 확인하여 모듈이 로드되었는지 확인할 수 있습니다. 그리고 모듈 이름을 키로 사용하여 딕셔너리에 액세스하면 모듈에 대한 정보를 얻을 수 있습니다.

  1. 다음 가져오기에서 Python 이 다시 로드하도록 하려면 이 딕셔너리에서 모듈을 제거할 수 있습니다. sys.modules 딕셔너리에서 모듈을 제거하면 Python 은 이미 모듈을 로드했음을 잊어버립니다. 따라서 다음에 가져오려고 하면 Python 은 소스 코드에서 다시 로드합니다.
>>> del sys.modules['simplemod']
>>> import simplemod
Loaded simplemod
>>> simplemod.x
42

sys.modules에서 모듈이 제거되었기 때문에 모듈이 다시 로드되었습니다. 이는 모듈 코드의 최신 버전을 사용하고 있는지 확인하는 또 다른 방법입니다.

from module import 구문 사용

Python 에는 모듈에서 구성 요소를 가져오는 다양한 방법이 있습니다. 이러한 방법 중 하나는 이 섹션에서 살펴볼 from module import 구문입니다.

모듈에서 구성 요소를 가져올 때는 깨끗한 상태로 시작하는 것이 좋습니다. 이렇게 하면 이전 상호 작용에서 남은 변수나 설정이 현재 실험을 방해할 수 없도록 보장합니다.

  1. 깨끗한 상태를 얻으려면 Python 인터프리터를 다시 시작합니다.
>>> exit()

이 명령은 현재 Python 인터프리터 세션을 종료합니다. 종료 후에는 새로운 환경을 보장하기 위해 새 세션을 시작합니다.

python3

이 bash 명령은 새 Python 3 인터프리터 세션을 시작합니다. 이제 깨끗한 Python 환경이 있으므로 모듈에서 구성 요소를 가져오기 시작할 수 있습니다.

  1. from module import 구문을 사용하여 모듈에서 특정 구성 요소를 가져옵니다.
>>> from simplemod import foo
Loaded simplemod
>>> foo()
x is 42

여기서는 from simplemod import foo 문을 사용하여 simplemod 모듈에서 foo 함수만 가져옵니다. foo 함수만 요청했지만 전체 simplemod 모듈이 로드되었음을 알 수 있습니다. 이는 "Loaded simplemod" 출력으로 표시됩니다. 이러한 이유는 Python 이 foo 함수에 액세스하기 위해 전체 모듈을 로드해야 하기 때문입니다.

  1. from module import를 사용하는 경우 모듈 자체에 액세스할 수 없습니다.
>>> simplemod.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'simplemod' is not defined

from module import 구문을 사용하면 지정된 구성 요소만 네임스페이스로 직접 가져옵니다. 모듈 이름 자체는 가져오지 않습니다. 따라서 simplemod.foo()에 액세스하려고 하면 Python 은 해당 방식으로 가져오지 않았기 때문에 simplemod를 인식하지 못합니다.

  1. 여러 구성 요소를 한 번에 가져올 수 있습니다.
>>> from simplemod import x, foo
>>> x
42
>>> foo()
x is 42

from module import 구문을 사용하면 단일 문에서 모듈에서 여러 구성 요소를 가져올 수 있습니다. 여기서는 simplemod 모듈에서 변수 x와 함수 foo를 모두 가져옵니다. 가져온 후에는 코드에서 이러한 구성 요소에 직접 액세스할 수 있습니다.

  1. 모듈에서 변수를 가져올 때 모듈의 변수에 대한 링크가 아닌 객체에 대한 새 참조를 생성합니다.
>>> x = 13  ## Change the local variable x
>>> x
13
>>> foo()
x is 42  ## The function still uses the module's x, not your local x

모듈에서 변수를 가져올 때 기본적으로 로컬 네임스페이스에서 동일한 객체에 대한 새 참조를 생성합니다. 따라서 로컬 변수 x13으로 변경해도 simplemod 모듈 내부의 x 변수에는 영향을 미치지 않습니다. foo() 함수는 여전히 모듈의 x 변수 (42) 를 참조합니다. 이 개념을 이해하는 것은 코드에서 혼란을 피하는 데 중요합니다.

모듈 다시 로딩 제한 사항 탐색

모듈 다시 로딩은 Python 에서 유용한 기능이지만 클래스를 다룰 때 특히 몇 가지 제한 사항이 있습니다. 이 섹션에서는 이러한 제한 사항을 단계별로 살펴보겠습니다. 이러한 제한 사항을 이해하는 것은 개발 및 프로덕션 환경 모두에서 중요합니다.

  1. Python 인터프리터를 다시 시작합니다. 먼저 Python 인터프리터를 다시 시작해야 합니다. 이 단계는 깨끗한 상태로 시작하기 때문에 중요합니다. 인터프리터를 다시 시작하면 이전에 가져온 모든 모듈과 변수가 지워집니다. 현재 Python 인터프리터를 종료하려면 exit() 명령을 사용합니다. 그런 다음 터미널에서 python3 명령을 사용하여 새 Python 인터프리터 세션을 시작합니다.
>>> exit()
python3
  1. 모듈을 가져오고 Spam 클래스의 인스턴스를 생성합니다. 이제 새로운 Python 인터프리터 세션이 있으므로 simplemod 모듈을 가져오겠습니다. 모듈을 가져오면 해당 모듈에 정의된 클래스, 함수 및 변수를 사용할 수 있습니다. 모듈을 가져온 후 Spam 클래스의 인스턴스를 생성하고 yow() 메서드를 호출합니다. 이렇게 하면 클래스의 초기 동작을 확인할 수 있습니다.
>>> import simplemod
Loaded simplemod
>>> s = simplemod.Spam()
>>> s.yow()
Yow!
  1. 이제 모듈에서 Spam 클래스를 수정해 보겠습니다. Python 인터프리터를 종료합니다. 다음으로 simplemod 모듈의 Spam 클래스를 변경할 것입니다. 그 전에 Python 인터프리터를 종료해야 합니다. 이는 모듈의 소스 코드를 변경한 다음 해당 변경 사항이 클래스의 동작에 어떤 영향을 미치는지 확인하려는 것이기 때문입니다.
>>> exit()
  1. WebIDE 에서 simplemod.py 파일을 열고 Spam 클래스를 수정합니다. WebIDE 에서 simplemod.py 파일을 엽니다. 여기에는 simplemod 모듈의 소스 코드가 있습니다. Spam 클래스의 yow() 메서드를 수정하여 다른 메시지를 출력합니다. 이 변경 사항은 모듈을 다시 로드한 후 클래스의 동작이 어떻게 변경되는지 관찰하는 데 도움이 됩니다.
## simplemod.py
## ... (leave the rest of the file unchanged)

class Spam:
    def yow(self):
        print('More Yow!')  ## Changed from 'Yow!'
  1. 파일을 저장하고 터미널로 돌아갑니다. Python 인터프리터를 시작하고 새 인스턴스를 생성합니다. simplemod.py 파일에 변경 사항을 적용한 후 저장합니다. 그런 다음 터미널로 돌아가 새 Python 인터프리터 세션을 시작합니다. simplemod 모듈을 다시 가져오고 Spam 클래스의 새 인스턴스를 생성합니다. 새 인스턴스의 yow() 메서드를 호출하여 업데이트된 동작을 확인합니다.
python3
>>> import simplemod
Loaded simplemod
>>> t = simplemod.Spam()
>>> t.yow()
More Yow!
  1. 이제 다시 로딩으로 어떤 일이 발생하는지 시연해 보겠습니다. 모듈 다시 로딩이 어떻게 작동하는지 확인하기 위해 importlib.reload() 함수를 사용합니다. 이 함수를 사용하면 이전에 가져온 모듈을 다시 로드할 수 있습니다. 모듈을 다시 로드한 후 Spam 클래스에 적용한 변경 사항이 반영되는지 확인합니다.
>>> import importlib
>>> importlib.reload(simplemod)
Loaded simplemod
<module 'simplemod' from 'simplemod.py'>
  1. Python 을 종료하고 파일을 다시 수정한 다음 두 인스턴스를 모두 테스트합니다. Python 인터프리터를 다시 종료합니다. 그런 다음 simplemod.py 파일의 Spam 클래스를 다시 변경합니다. 그 후 Spam 클래스의 이전 및 새 인스턴스를 모두 테스트하여 동작 방식을 확인합니다.
>>> exit()
  1. simplemod.py 파일을 업데이트합니다. simplemod.py 파일을 다시 열고 Spam 클래스의 yow() 메서드를 수정하여 다른 메시지를 출력합니다. 이 변경 사항은 모듈 다시 로딩의 제한 사항을 더 잘 이해하는 데 도움이 됩니다.
## simplemod.py
## ... (leave the rest of the file unchanged)

class Spam:
    def yow(self):
        print('Even More Yow!')  ## Changed again
  1. 파일을 저장하고 터미널로 돌아갑니다. simplemod.py 파일에 대한 변경 사항을 저장하고 터미널로 돌아갑니다. 새 Python 인터프리터 세션을 시작하고 simplemod 모듈을 가져온 다음 Spam 클래스의 새 인스턴스를 생성합니다. 새 인스턴스의 yow() 메서드를 호출하여 업데이트된 동작을 확인합니다.
python3
>>> import simplemod
Loaded simplemod
>>> s = simplemod.Spam()
>>> s.yow()
Even More Yow!

>>> ## Exit without closing Python, edit the file
  1. Python 을 닫지 않고 WebIDE 에서 simplemod.py를 열고 변경합니다. Python 인터프리터를 닫지 않고 WebIDE 에서 simplemod.py 파일을 열고 Spam 클래스의 yow() 메서드를 다시 변경합니다. 이렇게 하면 모듈을 다시 로드한 후 기존 및 새 인스턴스의 동작이 어떻게 변경되는지 확인할 수 있습니다.
## simplemod.py
## ... (leave the rest of the file unchanged)

class Spam:
    def yow(self):
        print('Super Yow!')  ## Changed one more time
  1. 파일을 저장하고 Python 인터프리터로 돌아갑니다. simplemod.py 파일에 대한 변경 사항을 저장하고 Python 인터프리터로 돌아갑니다. importlib.reload() 함수를 사용하여 simplemod 모듈을 다시 로드합니다. 그런 다음 Spam 클래스의 이전 및 새 인스턴스를 모두 테스트하여 동작 방식을 확인합니다.
>>> import importlib
>>> importlib.reload(simplemod)
Loaded simplemod
<module 'simplemod' from 'simplemod.py'>

>>> ## Try the old instance
>>> s.yow()
Even More Yow!  ## Still uses the old implementation

>>> ## Create a new instance
>>> t = simplemod.Spam()
>>> t.yow()
Super Yow!  ## Uses the new implementation

이전 인스턴스 s는 여전히 이전 구현을 사용하고 새 인스턴스 t는 새 구현을 사용한다는 것을 알 수 있습니다. 이는 모듈을 다시 로드해도 클래스의 기존 인스턴스가 업데이트되지 않기 때문에 발생합니다. 클래스 인스턴스가 생성되면 해당 시점의 클래스 객체에 대한 참조를 저장합니다. 모듈을 다시 로드하면 새 클래스 객체가 생성되지만 기존 인스턴스는 여전히 이전 클래스 객체를 참조합니다.

  1. 다른 특이한 동작도 관찰할 수 있습니다. isinstance() 함수를 사용하여 모듈 다시 로딩의 제한 사항을 더 자세히 관찰할 수 있습니다. 이 함수는 객체가 특정 클래스의 인스턴스인지 확인합니다. 모듈을 다시 로드한 후 이전 인스턴스 s는 더 이상 새 simplemod.Spam 클래스의 인스턴스로 간주되지 않고 새 인스턴스 t는 인스턴스로 간주되는 것을 확인할 수 있습니다.
>>> isinstance(s, simplemod.Spam)
False
>>> isinstance(t, simplemod.Spam)
True

이는 다시 로드한 후 simplemod.Spams를 생성하는 데 사용된 것과 다른 클래스 객체를 참조함을 나타냅니다.

이러한 제한 사항으로 인해 모듈 다시 로딩은 주로 개발 및 디버깅에 유용하며 프로덕션 코드에는 권장되지 않습니다. 프로덕션 환경에서는 클래스의 모든 인스턴스가 동일한 최신 구현을 사용하도록 보장하는 것이 중요합니다. 모듈 다시 로딩은 일관성 없는 동작으로 이어질 수 있으며, 이는 디버깅 및 유지 관리가 어려울 수 있습니다.

요약

이 Lab 에서 Python 에서 모듈을 사용하는 기본 사항을 배웠습니다. 변수, 함수 및 클래스를 사용하여 .py 파일로 Python 모듈을 생성하는 방법과 import 문을 사용하여 모듈을 가져오는 방법을 배웠습니다. 또한 Python 은 인터프리터 세션당 한 번만 모듈을 로드하며 importlib.reload()를 사용하여 강제로 다시 로드할 수 있다는 것을 이해했습니다.

또한 로드된 모듈을 추적하기 위해 sys.modules 딕셔너리를 탐색하고, 특정 구성 요소를 가져오기 위해 from module import 구문을 사용했으며, 특히 클래스와 관련하여 모듈 다시 로딩의 제한 사항을 파악했습니다. 이러한 개념은 Python 코드를 재사용 가능한 구성 요소로 구성하기 위한 기반이며, 이는 코드 구조를 유지하고 더 큰 애플리케이션에서 재사용성을 높이는 데 필수적입니다.