Организация больших программ с использованием функций

Intermediate

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

Введение

По мере того, как ваши программы становятся более крупными, вы захотите быть организованными. В этом разделе кратко介绍руются функции и библиотечные модули. Также介绍вается обработка ошибок с использованием исключений.

Это Guided Lab, который предоставляет пошаговые инструкции, чтобы помочь вам учиться и практиковаться. Внимательно следуйте инструкциям, чтобы выполнить каждый шаг и получить практический опыт. Исторические данные показывают, что это лабораторная работа уровня средний с процентом завершения 74%. Он получил 100% положительных отзывов от учащихся.

Пользовательские функции

Используйте функции для кода, который вы хотите повторно использовать. Вот определение функции:

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, чтобы улучшить свои навыки.