함수를 사용한 대규모 프로그램 구성

Intermediate

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

소개

프로그램의 규모가 커지기 시작하면, 체계적으로 정리하고 싶어질 것입니다. 이 섹션에서는 함수와 라이브러리 모듈을 간략하게 소개합니다. 예외를 사용한 오류 처리도 함께 소개합니다.

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

사용자 정의 함수 (Custom Functions)

재사용하려는 코드에는 함수를 사용하십시오. 다음은 함수 정의입니다.

def sumcount(n):
    '''
    Returns the sum of the first n integers
    '''
    total = 0
    while n > 0:
        total += n
        n -= 1
    return total

함수를 호출하려면 다음과 같이 합니다.

a = sumcount(100)

함수는 특정 작업을 수행하고 결과를 반환하는 일련의 문장입니다. return 키워드는 함수의 반환 값을 명시적으로 지정하는 데 필요합니다.

라이브러리 함수 (Library Functions)

Python 에는 방대한 표준 라이브러리가 포함되어 있습니다. 라이브러리 모듈은 import를 사용하여 접근합니다. 예를 들어:

import math
x = math.sqrt(10)

import urllib.request
u = urllib.request.urlopen('http://www.python.org/')
data = u.read()

라이브러리와 모듈에 대해서는 나중에 더 자세히 다루겠습니다.

오류와 예외 (Errors and exceptions)

함수는 오류를 예외 (exception) 로 보고합니다. 예외는 함수가 중단되도록 하며, 처리되지 않은 경우 전체 프로그램이 중지될 수 있습니다.

Python REPL 에서 다음을 시도해 보십시오.

>>> int('N/A')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'N/A'
>>>

디버깅 목적으로, 메시지는 무슨 일이 발생했는지, 오류가 어디에서 발생했는지, 그리고 실패로 이어진 다른 함수 호출을 보여주는 추적 (traceback) 을 설명합니다.

예외 포착 및 처리 (Catching and Handling Exceptions)

예외는 포착하고 처리할 수 있습니다.

포착하려면 try - except 문을 사용하십시오.

for line in file:
    fields = line.split(',')
    try:
        shares = int(fields[1])
    except ValueError:
        print("Couldn't parse", line)
    ...

ValueError의 이름은 포착하려는 오류의 종류와 일치해야 합니다.

수행되는 작업에 따라 어떤 종류의 오류가 발생할 수 있는지 미리 정확히 아는 것은 종종 어렵습니다. 좋든 싫든, 예외 처리는 종종 프로그램이 예기치 않게 충돌한 에 추가됩니다 (예: "아, 그 오류를 포착하는 것을 잊었네. 그걸 처리해야 해!").

예외 발생시키기 (Raising Exceptions)

예외를 발생시키려면 raise 문을 사용하십시오.

raise RuntimeError('What a kerfuffle')

이렇게 하면 try-except 블록에 의해 포착되지 않는 한, 프로그램이 예외 추적과 함께 중단됩니다.

% python3 foo.py
Traceback (most recent call last):
  File "foo.py", line 21, in <module>
    raise RuntimeError("What a kerfuffle")
RuntimeError: What a kerfuffle

연습 문제 1.29: 함수 정의하기 (Defining a function)

간단한 함수를 정의해 보십시오:

>>> def greeting(name):
        'Issues a greeting'
        print('Hello', name)

>>> greeting('Guido')
Hello Guido
>>> greeting('Paula')
Hello Paula
>>>

함수의 첫 번째 문이 문자열인 경우, 이는 문서로 사용됩니다. help(greeting)과 같은 명령을 입력하여 표시되는 내용을 확인해 보십시오.

연습 문제 1.30: 스크립트를 함수로 변환하기 (Turning a script into a function)

연습 문제 1.27 에서 pcost.py 프로그램에 대해 작성한 코드를 가져와서 portfolio_cost(filename) 함수로 변환하십시오. 이 함수는 파일 이름을 입력으로 받아 해당 파일의 포트폴리오 데이터를 읽고 포트폴리오의 총 비용을 float 로 반환합니다.

함수를 사용하려면 프로그램을 다음과 같이 변경하십시오:

## pcost.py
def portfolio_cost(filename):
    """
    Computes the total cost (shares*price) of a portfolio file
    """
    total_cost = 0.0

    with open(filename, "rt") as f:
        rows = f.readlines()
        headers = rows[0].strip().split(",")
        for row in rows[1:]:
            row_data = row.strip().split(",")
            nshares = int(row_data[1])
            price = float(row_data[2])
            total_cost += nshares * price

    return total_cost


import sys

if len(sys.argv) == 2:
    filename = sys.argv[1]
else:
    filename = input("Enter a filename:")

cost = portfolio_cost(filename)
print("Total cost:", cost)

프로그램을 실행하면 이전과 동일한 출력을 볼 수 있습니다. 프로그램을 실행한 후에는 다음과 같이 입력하여 함수를 대화형으로 호출할 수도 있습니다:

$ python3 -i pcost.py

이렇게 하면 대화형 모드에서 함수를 호출할 수 있습니다.

>>> portfolio_cost('portfolio.csv')
44671.15
>>>

코드를 대화형으로 실험할 수 있는 것은 테스트 및 디버깅에 유용합니다.

연습 문제 1.31: 오류 처리 (Error handling)

필드가 누락된 파일에서 함수를 시도하면 어떻게 될까요?

>>> portfolio_cost('missing.csv')
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "pcost.py", line 11, in portfolio_cost
    nshares    = int(fields[1])
ValueError: invalid literal for int() with base 10: ''
>>>

이 시점에서 결정을 내려야 합니다. 프로그램을 작동시키려면 잘못된 줄을 제거하여 원래 입력 파일을 정리하거나, 일부 방식으로 잘못된 줄을 처리하도록 코드를 수정할 수 있습니다.

pcost.py 프로그램을 수정하여 예외를 포착하고, 경고 메시지를 인쇄한 다음 파일의 나머지 부분을 계속 처리하십시오.

연습 문제 1.32: 라이브러리 함수 사용하기 (Using a library function)

Python 에는 유용한 함수가 포함된 대규모 표준 라이브러리가 있습니다. 여기서 유용할 수 있는 라이브러리 중 하나는 csv 모듈입니다. CSV 데이터 파일로 작업해야 할 때마다 이 모듈을 사용해야 합니다. 다음은 작동 방식의 예입니다:

>>> import csv
>>> f = open('portfolio.csv')
>>> rows = csv.reader(f)
>>> headers = next(rows)
>>> headers
['name', 'shares', 'price']
>>> for row in rows:
        print(row)

['AA', '100', '32.20']
['IBM', '50', '91.10']
['CAT', '150', '83.44']
['MSFT', '200', '51.23']
['GE', '95', '40.37']
['MSFT', '50', '65.10']
['IBM', '100', '70.44']
>>> f.close()
>>>

csv 모듈의 좋은 점 중 하나는 따옴표 처리 및 쉼표 분할과 같은 다양한 하위 수준 세부 사항을 처리한다는 것입니다. 위의 출력에서 첫 번째 열의 이름에서 큰따옴표가 제거된 것을 확인할 수 있습니다.

pcost.py 프로그램을 수정하여 구문 분석에 csv 모듈을 사용하고 이전 예제를 실행해 보십시오.

연습 문제 1.33: 명령줄에서 읽기 (Reading from the command line)

pcost.py 프로그램에서 입력 파일의 이름은 코드에 하드코딩되어 있습니다:

## pcost.py

def portfolio_cost(filename):
    ...
    ## Your code here
    ...

cost = portfolio_cost('portfolio.csv')
print('Total cost:', cost)

이는 학습 및 테스트에는 괜찮지만, 실제 프로그램에서는 그렇게 하지 않을 것입니다.

대신, 스크립트에 인수로 파일 이름을 전달할 수 있습니다. 프로그램의 하단 부분을 다음과 같이 변경해 보십시오:

## pcost_1.33.py

import csv


def portfolio_cost(filename):
    """
    Computes the total cost (shares*price) of a portfolio file
    """
    total_cost = 0.0

    with open(filename, "rt") as f:
        rows = csv.reader(f)
        headers = next(rows)  ## Skip header row
        for row in rows:
            if len(row) < 3:
                print("Skipping invalid row:", row)
                continue
            try:
                nshares = int(row[1])
                price = float(row[2])
                total_cost += nshares * price
            except (IndexError, ValueError):
                print("Skipping invalid row:", row)

    return total_cost

import sys


if len(sys.argv) == 2:
    filename = sys.argv[1]
else:
    filename = 'portfolio.csv'

cost = portfolio_cost(filename)
print('Total cost:', cost)

sys.argv는 명령줄에서 전달된 인수 (있는 경우) 를 포함하는 목록입니다.

프로그램을 실행하려면 터미널에서 Python 을 실행해야 합니다.

예를 들어, Unix 의 bash 에서:

$ python3 pcost.py portfolio.csv
Total cost: 44671.15
bash %

요약 (Summary)

축하합니다! 함수 랩을 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 실력을 향상시킬 수 있습니다.