함수를 사용한 모듈 프로그래밍

Beginner

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

소개

이 섹션에서는 모듈의 개념과 여러 파일에 걸쳐 있는 함수 작업에 대해 소개합니다.

이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 초급 레벨의 실험이며 완료율은 82%입니다.학습자들로부터 100%의 긍정적인 리뷰율을 받았습니다.

모듈과 import

모든 Python 소스 파일은 모듈입니다.

## foo.py
def grok(a):
    ...
def spam(b):
    ...

import 문은 모듈을 로드하고 실행합니다.

## program.py
import foo

a = foo.grok(2)
b = foo.spam('Hello')
...

네임스페이스 (Namespace)

모듈은 명명된 값들의 집합이며, 때로는 네임스페이스라고 불립니다. 이름은 소스 파일에 정의된 모든 전역 변수와 함수입니다. import 후, 모듈 이름은 접두사로 사용됩니다. 따라서 네임스페이스입니다.

import foo

a = foo.grok(2)
b = foo.spam('Hello')
...

모듈 이름은 파일 이름과 직접적으로 연결됩니다 (foo -> foo.py).

전역 정의 (Global Definitions)

전역 범위에서 정의된 모든 것은 모듈 네임스페이스를 채웁니다. 동일한 변수 x를 정의하는 두 개의 모듈을 생각해 봅시다.

## foo.py
x = 42
def grok(a):
    ...
## bar.py
x = 37
def spam(a):
    ...

이 경우, x 정의는 서로 다른 변수를 참조합니다. 하나는 foo.x이고 다른 하나는 bar.x입니다. 서로 다른 모듈은 동일한 이름을 사용할 수 있으며, 해당 이름들은 서로 충돌하지 않습니다.

모듈은 격리되어 있습니다.

환경으로서의 모듈 (Modules as Environments)

모듈은 내부에 정의된 모든 코드에 대한 묶는 환경을 형성합니다.

## foo.py
x = 42

def grok(a):
    print(x)

전역 변수는 항상 묶는 모듈 (동일한 파일) 에 바인딩됩니다. 각 소스 파일은 자체적인 작은 우주입니다.

모듈 실행 (Module Execution)

모듈이 임포트되면, 모듈 내의 모든 구문이 파일 끝에 도달할 때까지 하나씩 차례로 실행됩니다. 모듈 네임스페이스의 내용은 실행 프로세스가 끝날 때까지 여전히 정의된 모든 전역 이름입니다. 전역 범위에서 작업을 수행하는 스크립팅 구문 (출력, 파일 생성 등) 이 있는 경우, 임포트 시 실행되는 것을 볼 수 있습니다.

import as 구문

모듈을 임포트할 때 이름을 변경할 수 있습니다:

import math as m
def rectangular(r, theta):
    x = r * m.cos(theta)
    y = r * m.sin(theta)
    return x, y

이는 일반적인 import 와 동일하게 작동합니다. 단지 해당 파일 내에서 모듈의 이름을 변경할 뿐입니다.

from 모듈 임포트

이것은 모듈에서 선택된 심볼을 가져와 로컬에서 사용할 수 있도록 합니다.

from math import sin, cos

def rectangular(r, theta):
    x = r * cos(theta)
    y = r * sin(theta)
    return x, y

이를 통해 모듈 접두어를 입력하지 않고도 모듈의 일부를 사용할 수 있습니다. 자주 사용되는 이름에 유용합니다.

임포트에 대한 주석

import 의 변형은 모듈의 작동 방식을 변경하지 않습니다.

import math
## vs
import math as m
## vs
from math import cos, sin
...

구체적으로, import는 항상 전체 파일을 실행하며 모듈은 여전히 격리된 환경입니다.

import module as 구문은 로컬에서 이름만 변경합니다. from math import cos, sin 구문은 여전히 백그라운드에서 전체 math 모듈을 로드합니다. 이는 단순히 완료된 후 cossin 이름을 모듈에서 로컬 공간으로 복사하는 것입니다.

모듈 로딩

각 모듈은 한 번만 로드되고 실행됩니다. 참고: 반복적인 import 는 이전에 로드된 모듈에 대한 참조를 반환합니다.

sys.modules는 로드된 모든 모듈의 딕셔너리입니다.

>>> import sys
>>> sys.modules.keys()
['copy_reg', '__main__', 'site', '__builtin__', 'encodings', 'encodings.encodings', 'posixpath', ...]
>>>

주의: 모듈의 소스 코드를 변경한 후 import 문을 반복하면 흔히 혼란이 발생합니다. 모듈 캐시 sys.modules 때문에 반복적인 import 는 변경이 이루어졌더라도 항상 이전에 로드된 모듈을 반환합니다. 수정된 코드를 Python 에 로드하는 가장 안전한 방법은 인터프리터를 종료하고 다시 시작하는 것입니다.

모듈 찾기

Python 은 모듈을 찾을 때 경로 목록 (sys.path) 을 참조합니다.

>>> import sys
>>> sys.path
[
  '',
  '/usr/local/lib/python36/python36.zip',
  '/usr/local/lib/python36',
  ...
]

현재 작업 디렉토리가 일반적으로 먼저 옵니다.

모듈 검색 경로

앞서 언급했듯이, sys.path에는 검색 경로가 포함되어 있습니다. 필요에 따라 수동으로 조정할 수 있습니다.

import sys
sys.path.append('/project/foo/pyfiles')

환경 변수를 통해 경로를 추가할 수도 있습니다.

% env PYTHONPATH=/project/foo/pyfiles python3
Python 3.6.0 (default, Feb 3 2017, 05:53:21)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)]
>>> import sys
>>> sys.path
['','/project/foo/pyfiles', ...]

일반적으로 모듈 검색 경로를 수동으로 조정할 필요는 없습니다. 그러나 특이한 위치에 있거나 현재 작업 디렉토리에서 쉽게 접근할 수 없는 Python 코드를 import 하려는 경우에 발생할 수 있습니다.

모듈과 관련된 이 연습에서는 적절한 환경에서 Python 을 실행하고 있는지 확인하는 것이 매우 중요합니다. 모듈은 종종 새로운 프로그래머에게 현재 작업 디렉토리 또는 Python 의 경로 설정과 관련된 문제를 제시합니다. 이 과정에서는 모든 코드를 ~/project 디렉토리에서 작성한다고 가정합니다. 최상의 결과를 얻으려면 인터프리터를 시작할 때 해당 디렉토리에도 있는지 확인해야 합니다. 그렇지 않은 경우 ~/projectsys.path에 추가되었는지 확인해야 합니다.

연습 문제 3.11: 모듈 import

3 장에서 CSV 데이터 파일의 내용을 파싱하기 위한 범용 함수 parse_csv()를 만들었습니다.

이제 해당 함수를 다른 프로그램에서 사용하는 방법을 살펴보겠습니다. 먼저, 새 셸 창을 시작합니다. 모든 파일이 있는 폴더로 이동합니다. 파일을 import 할 것입니다.

Python 대화형 모드를 시작합니다.

$ python3
Python 3.6.1 (v3.6.1:69c0db5050, Mar 21 2017, 01:21:04)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

그렇게 했다면, 이전에 작성한 프로그램 중 일부를 import 해 보세요. 이전과 정확히 동일한 출력을 볼 수 있습니다. 강조하자면, 모듈을 import 하면 해당 코드가 실행됩니다.

>>> import bounce
... watch output ...
>>> import mortgage
... watch output ...
>>> import report
... watch output ...
>>>

이 중 어느 것도 작동하지 않으면, 아마도 잘못된 디렉토리에서 Python 을 실행하고 있을 것입니다. 이제 fileparse 모듈을 import 하고 이에 대한 도움말을 얻어보세요.

>>> import fileparse
>>> help(fileparse)
... look at the output ...
>>> dir(fileparse)
... look at the output ...
>>>

모듈을 사용하여 일부 데이터를 읽어보세요:

>>> portfolio = fileparse.parse_csv('/home/labex/project/portfolio.csv',select=['name','shares','price'], types=[str,int,float])
>>> portfolio
... look at the output ...
>>> pricelist = fileparse.parse_csv('/home/labex/project/prices.csv',types=[str,float], has_headers=False)
>>> pricelist
... look at the output ...
>>> prices = dict(pricelist)
>>> prices
... look at the output ...
>>> prices['IBM']
106.28
>>>

모듈 이름을 포함할 필요가 없도록 함수를 import 해 보세요:

>>> from fileparse import parse_csv
>>> portfolio = parse_csv('/home/labex/project/portfolio.csv', select=['name','shares','price'], types=[str,int,float])
>>> portfolio
... look at the output ...
>>>

연습 문제 3.12: 라이브러리 모듈 사용

2 장에서 다음과 같은 주식 보고서를 생성하는 프로그램 report.py를 작성했습니다.

      Name     Shares      Price     Change
---------- ---------- ---------- ----------
        AA        100       9.22     -22.98
       IBM         50     106.28      15.18
       CAT        150      35.46     -47.98
      MSFT        200      20.89     -30.34
        GE         95      13.48     -26.89
      MSFT         50      20.89     -44.21
       IBM        100     106.28      35.84

해당 프로그램을 가져와서 모든 입력 파일 처리가 fileparse 모듈의 함수를 사용하여 수행되도록 수정합니다. 이를 위해 fileparse를 모듈로 import 하고 read_portfolio()read_prices() 함수를 변경하여 parse_csv() 함수를 사용합니다.

이 연습의 시작 부분에 있는 대화형 예제를 가이드로 사용하세요. 그런 다음, 이전과 정확히 동일한 출력을 얻어야 합니다.

연습 문제 3.13: 의도적으로 비워 둠 (건너뛰기)

연습 문제 3.14: 더 많은 라이브러리 import 사용

1 장에서 포트폴리오를 읽고 비용을 계산하는 프로그램 pcost.py를 작성했습니다.

>>> import pcost
>>> pcost.portfolio_cost('/home/labex/project/portfolio.csv')
44671.15
>>>

pcost.py 파일을 수정하여 report.read_portfolio() 함수를 사용하도록 합니다.

해설

이 연습 문제를 완료하면 세 개의 프로그램이 있어야 합니다. 범용 parse_csv() 함수를 포함하는 fileparse.py. 멋진 보고서를 생성하지만 read_portfolio()read_prices() 함수도 포함하는 report.py. 마지막으로, 포트폴리오 비용을 계산하지만 report.py 프로그램용으로 작성된 read_portfolio() 함수를 사용하는 pcost.py.

요약

축하합니다! 모듈 랩을 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 기술을 향상시킬 수 있습니다.