소개
프로그램의 규모가 커지기 시작하면, 체계적으로 정리하고 싶어질 것입니다. 이 섹션에서는 함수와 라이브러리 모듈을 간략하게 소개합니다. 예외를 사용한 오류 처리도 함께 소개합니다.
사용자 정의 함수 (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 에서 더 많은 랩을 연습하여 실력을 향상시킬 수 있습니다.