Глава 8 • Функции
usernames = ['hannah', 'ty', 'margot']
greet_users(usernames)
В соответствии со своим определением функция
greet_users()
рассчитывает полу-
чить список имен, который сохраняется в параметре
names
. Функция перебирает
полученный список и выводит приветствие для каждого пользователя. В точке
мы определяем список пользователей
usernames
, который затем передается
greet_
users()
в вызове функции:
Hello, Hannah!
Hello, Ty!
Hello, Margot!
Результат выглядит именно так, как ожидалось. Каждый пользователь получает
персональное сообщение, и эту функцию можно вызвать для каждого нового на-
бора пользователей.
Изменение списка в функции
Если вы передаете список функции, код функции сможет изменить список. Все
изменения, внесенные в список в теле функции, закрепляются, что позволяет эф-
фективно работать со списком даже при больших объемах данных.
Допустим, компания печатает на 3D-принтере модели, предоставленные пользо-
вателем. Проекты хранятся в списке, а после печати перемещаются в отдельный
список. В следующем примере приведена реализация, не использующая функции:
printing_models.py
# Список моделей, которые необходимо напечатать.
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_models = []
# Цикл последовательно печатает каждую модель до конца списка.
# После печати каждая модель перемещается в список completed_models.
while unprinted_designs:
current_design = unprinted_designs.pop()
# Печать модели на 3D-принтере.
print("Printing model: " + current_design)
completed_models.append(current_design)
# Вывод всех готовых моделей.
print("\nThe following models have been printed:")
for completed_model in completed_models:
print(completed_model)
В начале программы создается список моделей и пустой список
completed_models
,
в который каждая модель перемещается после печати. Пока в
unprinted_designs
остаются модели, цикл
while
имитирует печать каждой модели: модель удаляется
с конца списка, сохраняется в
current_design
, а пользователь получает сообщение
о том, что текущая модель была напечатана. Затем модель перемещается в спи-
сок напечатанных. После завершения цикла выводится список напечатанных
моделей:
Передача списка
149
Printing model: dodecahedron
Printing model: robot pendant
Printing model: iphone case
The following models have been printed:
dodecahedron
robot pendant
iphone case
Мы можем изменить структуру этого кода: для этого следует написать две функ-
ции, каждая из которых решает одну конкретную задачу. Б
у
льшая часть кода
останется неизменной; просто программа становится более эффективной. Первая
функция занимается печатью, а вторая выводит сводку напечатанных моделей:
def print_models(unprinted_designs, completed_models):
"""
Имитирует печать моделей, пока список не станет пустым.
Каждая модель после печати перемещается в completed_models.
"""
while unprinted_designs:
current_design = unprinted_designs.pop()
# Имитация печати модели на 3D-принтере.
print("Printing model: " + current_design)
completed_models.append(current_design)
def show_completed_models(completed_models):
"""Выводит информацию обо всех напечатанных моделях."""
print("\nThe following models have been printed:")
for completed_model in completed_models:
print(completed_model)
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_models = []
print_models(unprinted_designs, completed_models)
show_completed_models(completed_models)
В точке
определяется функция
print_models()
с двумя параметрами: список
моделей для печати и список готовых моделей. Функция имитирует печать каж-
дой модели, последовательно извлекая модели из первого списка и перемещая
их во второй список. В точке
определяется функция
show_completed_models()
с одним параметром: списком напечатанных моделей. Функция
show_completed_
models()
получает этот список и выводит имена всех напечатанных моделей.
Программа выводит тот же результат, что и версия без функций, но структура
кода значительно улучшилась. Код, выполняющий б
у
льшую часть работы, разне-
сен по двум разным функциям; это упрощает чтение основной части программы.
Теперь любому разработчику будет намного проще просмотреть код программы
и понять, что делает программа:
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_models = []
print_models(unprinted_designs, completed_models)
show_completed_models(completed_models)
150
Глава 8 • Функции
Программа создает список моделей для печати и пустой список для готовых моде-
лей. Затем, поскольку обе функции уже определены, остается вызвать их и передать
правильные аргументы. Мы вызываем
print_models()
и передаем два необходимых
списка; как и ожидалось,
print_models()
имитирует печать моделей. Затем вызыва-
ется функция
show_completed_models()
, и ей передается список готовых моделей,
чтобы функция могла вывести информацию о напечатанных моделях. Благодаря
содержательным именам функций другой разработчик сможет прочитать этот код
и понять его даже без комментариев.
Вдобавок эта программа создает меньше проблем с расширением и сопровождени-
ем, чем версия без функций. Если позднее потребуется напечатать новую партию
моделей, достаточно снова вызвать
print_models()
. Если окажется, что код печати
необходимо модифицировать, изменения достаточно внести в одном месте, и они
автоматически распространятся на все вызовы функции. Такой подход намного
эффективнее независимой правки кода в нескольких местах программы.
Этот пример также демонстрирует принцип, в соответствии с которым каждая
функция должна решать одну конкретную задачу. Первая функция печатает
каждую модель, а вторая выводит информацию о готовых моделях. Такой подход
предпочтительнее решения обеих задач в функции. Если вы пишете функцию
и видите, что она решает слишком много разных задач, попробуйте разделить ее
код на две функции.
Помните, что функции всегда можно вызывать из других функций. Эта возмож-
ность может пригодиться для разбиения сложных задач на серию составляющих.
Запрет изменения списка в функции
Иногда требуется предотвратить изменение списка в функции. Допустим, у вас
имеется список моделей для печати, и вы пишете функцию для перемещения их
в список готовых моделей, как в предыдущем примере. Возможно, даже после пе-
чати всех моделей исходный список нужно оставить для отчетности. Но, поскольку
все имена моделей были перенесены из списка
unprinted_designs
, остался только
пустой список; исходная версия списка потеряна. Проблему можно решить пере-
дачей функции копии списка вместо оригинала. В этом случае все изменения,
вносимые функцией в список, будут распространяться только на копию, а оригинал
списка остается неизменным.
Чтобы передать функции копию списка, можно поступить так:
имя_функции
(
имя_списка
[:])
Синтаксис среза
[:]
создает копию списка для передачи функции. Если удаление
элементов из списка
unprinted_designs
в
print_models .py
нежелательно, функцию
print_models()
можно вызвать так:
print_models(unprinted_designs[:], completed_models)
Функция
print_models()
может выполнить свою работу, потому что она все равно
получает имена всех ненапечатаных моделей. Но на этот раз она получает не сам
список
unprinted_designs
, а его копию. Список
completed_models
заполняется
Передача списка
151
именами напечатанных моделей, как и в предыдущем случае, но исходный список
функцией не изменяется.
Несмотря на то что передача копии позволяет сохранить содержимое списка, обыч-
но функциям следует передавать исходный список (если у вас нет веских причин
для передачи копии). Работа с существующим списком более эффективна, потому
что программе не приходится тратить время и память на создание отдельной копии
(лишние затраты особенно заметны при работе с большими списками).
Достарыңызбен бөлісу: |