Введение
По мере того, как ваши программы становятся более крупными, вы захотите быть организованными. В этом разделе кратко介绍руются функции и библиотечные модули. Также介绍вается обработка ошибок с использованием исключений.
Пользовательские функции
Используйте функции для кода, который вы хотите повторно использовать. Вот определение функции:
def sumcount(n):
'''
Возвращает сумму первых n целых чисел
'''
total = 0
while n > 0:
total += n
n -= 1
return total
Для вызова функции.
a = sumcount(100)
Функция - это серия инструкций, которые выполняют какую - то задачу и возвращают результат. Ключевое слово return необходимо для явного указания возвращаемого значения функции.
Библиотечные функции
Python поставляется с большим стандартным библиотекой. Библиотечные модули доступны с использованием import. Например:
import math
x = math.sqrt(10)
import urllib.request
u = urllib.request.urlopen('http://www.python.org/')
data = u.read()
Мы рассмотрим библиотеки и модули более подробно позже.
Ошибки и исключения
Функции сообщают об ошибках в виде исключений. Исключение заставляет функцию прервать выполнение и может привести к остановке всей программы, если оно не обработано.
Попробуйте это в вашем 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'
>>>
Для целей отладки сообщение описывает, что произошло, где возникла ошибка и трассировку стека, показывающую другие вызовы функций, которые привели к неудаче.
Захват и обработка исключений
Исключения можно ловить и обрабатывать.
Для захвата используйте оператор try - except.
for line in file:
fields = line.split(',')
try:
shares = int(fields[1])
except ValueError:
print("Couldn't parse", line)
...
Имя ValueError должно совпадать с типом ошибки, которую вы пытаетесь поймать.
Часто трудно заранее точно знать, какие виды ошибок могут возникнуть, в зависимости от выполняемой операции. Хорошо или плохо, обработка исключений часто добавляется после того, как программа внезапно завершилась сбоем (то есть "о, мы забыли поймать эту ошибку. Мы должны обработать ее!").
Генерация исключений
Для генерации исключения используйте оператор 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: Определение функции
Попробуйте определить простую функцию:
>>> def greeting(name):
'Issues a greeting'
print('Hello', name)
>>> greeting('Guido')
Hello Guido
>>> greeting('Paula')
Hello Paula
>>>
Если первое выражение функции - это строка, то она служит в качестве документации. Попробуйте ввести команду, например, help(greeting), чтобы увидеть ее отображение.
Упражнение 1.30: Преобразование скрипта в функцию
Возьмите код, который вы написали для программы pcost.py в упражнении 1.27, и преобразуйте его в функцию portfolio_cost(filename). Эта функция принимает имя файла в качестве входных данных, читает данные портфеля из этого файла и возвращает общую стоимость портфеля в виде числа с плавающей точкой.
Для использования вашей функции измените вашу программу так, чтобы она выглядела примерно так:
## 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: Обработка ошибок
Что произойдет, если вы попытаетесь применить свою функцию к файлу с некоторыми пропущенными полями?
>>> 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: Использование функции из библиотеки
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: Чтение из командной строки
В программе pcost.py имя входного файла жестко закодировано в код:
## pcost.py
def portfolio_cost(filename):
...
## Ваш код здесь
...
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) ## Пропустить строку с заголовками
for row in rows:
if len(row) < 3:
print("Пропускаю недействительную строку:", row)
continue
try:
nshares = int(row[1])
price = float(row[2])
total_cost += nshares * price
except (IndexError, ValueError):
print("Пропускаю недействительную строку:", 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 из терминала.
Например, из bash на Unix:
$ python3 pcost.py portfolio.csv
Total cost: 44671.15
bash %
Резюме
Поздравляем! Вы завершили лабораторную работу по функциям. Вы можете практиковаться в более лабораторных работах в LabEx, чтобы улучшить свои навыки.