Главная страница

Книга Изучаем Python


Скачать 4.68 Mb.
НазваниеКнига Изучаем Python
Дата10.12.2022
Размер4.68 Mb.
Формат файлаpdf
Имя файлаErik_Metiz_Izuchaem_Python_Programmirovanie_igr_vizualizatsia_da.pdf
ТипКнига
#837531
страница17 из 53
1   ...   13   14   15   16   17   18   19   20   ...   53
ПРИМЕЧАНИЕ
На самом деле не так важно, какой стиль вызова вы используете . Если ваша функция выдает нуж- ный результат, выберите тот стиль, который вам кажется более понятным .
Предотвращение ошибок в аргументах
Не удивляйтесь, если на первых порах вашей работы с функциями будут встре- чаться ошибки несоответствия аргументов. Такие ошибки происходят в том слу- чае, если вы передали меньше или больше аргументов, чем необходимо функции для выполнения ее работы. Например, вот что произойдет при попытке вызвать describe_pet()
без аргументов:
def describe_pet(animal_type, pet_name):
"""Выводит информацию о животном."""
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet()

142 Глава 8 • Функции
Python понимает, что при вызове функции часть информации отсутствует, и мы видим это в данных трассировки:
Traceback (most recent call last):

File "pets.py", line 6, in
 describe_pet()

TypeError: describe_pet() missing 2 required positional arguments:
'animal_
type' and 'pet_name'
В точке  сообщается местонахождение проблемы, чтобы вы поняли, что с вызовом функции что-то пошло не так. В точке  приводится вызов функции, приведший к ошибке. В точке  Python сообщает, что при вызове пропущены два аргумента, и сообщает имена этих аргументов. Если бы функция размещалась в отдельном файле, вероятно, вы смогли бы исправить вызов, и вам не пришлось бы открывать этот файл и читать код функции.
Python помогает еще и тем, что он читает код функции и сообщает имена аргумен- тов, которые необходимо передать при вызове. Это еще одна причина для того, чтобы присваивать переменным и функциям содержательные имена. В этом случае сообщения об ошибках Python принесут больше пользы как вам, так и любому другому разработчику, который будет использовать ваш код.
Если при вызове будут переданы лишние аргументы, вы получите похожую трассировку, которая поможет привести вызов функции в соответствие с ее определением.
УПРАЖНЕНИЯ
8-3 . Футболка: напишите функцию make_shirt(), которая получает размер футболки и текст, который должен быть напечатан на ней . Функция должна выводить сообщение с размером и текстом . Вызовите функцию с использованием позиционных аргументов . Вызовите функ- цию во второй раз с использованием именованных аргументов .
8-4 . Большие футболки: измените функцию make_shirt(), чтобы футболки по умолчанию имели размер L, и на них выводился текст «I love Python .» . Создайте футболку с размером
L и текстом по умолчанию, а также футболку любого размера с другим текстом .
8-5 . Города: напишите функцию describe_city(), которая получает названия города и стра- ны . Функция должна выводить простое сообщение (например, «Reykjavik is in Iceland») . За- дайте параметру страны значение по умолчанию . Вызовите свою функцию для трех разных городов, по крайней мере один из которых не находится в стране по умолчанию .
Возвращаемое значение
Функция не обязана выводить результаты своей работы. Вместо этого она может обработать данные, а затем вернуть значение или набор сообщений. Значение, возвращаемое функцией, называется возвращаемым значением. Команда return передает значение из функции в строку, в которой эта функция была вызвана.
Возвращаемые значения помогают переместить бульшую часть рутинной работы в вашей программе в функции, чтобы упростить основной код программы.

Возвращаемое значение 143
Возвращение простого значения
Рассмотрим функцию, которая получает имя и фамилию и возвращает аккуратно отформатированное полное имя:
formatted_name.py
 def get_formatted_name(first_name, last_name):
"""Возвращает аккуратно отформатированное полное имя."""
 full_name = first_name + ' ' + last_name
 return full_name.title()
 musician = get_formatted_name('jimi', 'hendrix')
print(musician)
Определение get_formatted_name()
получает в параметрах имя и фамилию .
Функция объединяет эти два имени, добавляет между ними пробел и сохраняет результат в full_name
. Значение full_name преобразуется в формат с начальной буквой верхнего регистра, а затем возвращается в точку вызова .
Вызывая функцию, которая возвращает значение, необходимо предоставить пере- менную, в которой должно храниться возвращаемое значение. В данном случае возвращаемое значение сохраняется в переменной musician
. Результат содержит аккуратно отформатированное полное имя, построенное из имени и фамилии:
Jimi Hendrix
Может показаться, что все эти хлопоты излишни — с таким же успехом можно было использовать команду:
print("Jimi Hendrix")
Но если представить, что вы пишете большую программу, в которой многочис- ленные имена и фамилии должны храниться по отдельности, такие функции, как get_formatted_name()
, становятся чрезвычайно полезными. Вы храните имена отдельно от фамилий, а затем вызываете функцию везде, где потребуется вывести полное имя.
Необязательные аргументы
Иногда бывает удобно сделать аргумент необязательным, чтобы разработчик, ис- пользующий функцию, мог передать дополнительную информацию только в том случае, если он этого захочет. Чтобы сделать аргумент необязательным, можно воспользоваться значением по умолчанию. Допустим, вы захотели расширить функцию get_formatted_name()
, чтобы она также работала и со вторыми именами.
Первая попытка могла бы выглядеть так:
def get_formatted_name(first_name, middle_name, last_name):
"""Возвращает аккуратно отформатированное полное имя."""
full_name = first_name + ' ' + middle_name + ' ' + last_name return full_name.title()
musician = get_formatted_name('john', 'lee', 'hooker')
print(musician)

144 Глава 8 • Функции
Функция работает при получении имени, второго имени и фамилии. Она получает все три части имени, а затем строит из них строку. Функция добавляет пробелы там, где это уместно, и преобразует полное имя в формат с капитализацией:
John Lee Hooker
Однако вторые имена нужны не всегда, а в такой записи функция не будет работать, если при вызове ей передаются только имя и фамилия. Чтобы средний аргумент был необязательным, можно присвоить аргументу middle_name пустое значение по умолчанию; этот аргумент игнорируется, если пользователь не передал для него значение. Чтобы функция get_formatted_name()
работала без второго имени, сле- дует назначить для параметра middle_name пустую строку значением по умолчанию и переместить его в конец списка параметров:
 def get_formatted_name(first_name, last_name, middle_name=''):
"""Возвращает аккуратно отформатированное полное имя."""
 if middle_name:
full_name = first_name + ' ' + middle_name + ' ' + last_ name
 else:
full_name = first_name + ' ' + last_name return full_name.title()
musician = get_formatted_name('jimi', 'hendrix')
print(musician)
 musician = get_formatted_name('john', 'hooker', 'lee')
print(musician)
В этом примере имя строится из трех возможных частей. Поскольку имя и фамилия указываются всегда, эти параметры стоят в начале списка в определении функции.
Второе имя не обязательно, поэтому оно находится на последнем месте в опреде- лении, а его значением по умолчанию является пустая строка .
В теле функции мы сначала проверяем, было ли задано второе имя. Python ин- терпретирует непустые строки как истинное значение, и, если при вызове задан аргумент второго имени, middle_name дает результат
True
. Если второе имя указано, то из имени, второго имени и фамилии строится полное имя. Затем имя преобразуется с капитализацией символов и возвращается в строку вызова функ- ции, где оно сохраняется в переменной musician и выводится. Если второе имя не указано, то пустая строка не проходит проверку if и выполняет блок else
. В этом случае полное имя строится только из имени и фамилии, и отформатированное имя возвращается в строку вызова, где оно сохраняется в переменной musician и выводится.
Вызов этой функции с именем и фамилией достаточно тривиален. Но при ис- пользовании второго имени придется проследить за тем, чтобы второе имя было последним из передаваемых аргументов. Это необходимо для правильного связы- вания позиционных аргументов в строке .
Обновленная версия этой функции подойдет как для людей, у которых задается только имя и фамилия, так и для людей со вторым именем:

Возвращаемое значение 145
Jimi Hendrix
John Lee Hooker
Необязательные значения позволяют функциям работать в максимально широком спектре сценариев использования без усложнения вызовов.
Возвращение словаря
Функция может вернуть любое значение, нужное вам, в том числе и более сложную структуру данных (например, список или словарь). Так, следующая функция полу- чает части имени и возвращает словарь, представляющий человека:
person.py
def build_person(first_name, last_name):
"""Возвращает словарь с информацией о человеке."""
 person = {'first': first_name, 'last': last_name}
 return person musician = build_person('jimi', 'hendrix')
 print(musician)
Функция build_person()
получает имя и фамилию и сохраняет полученные зна- чения в словаре в точке . Значение first_name сохраняется с ключом 'first'
, а значение last_name
— с ключом 'last'
. Весь словарь с описанием человека возвращается в точке . Возвращаемое значение выводится в точке  с двумя исходными фрагментами текстовой информации, теперь хранящимися в словаре:
{'first': 'jimi', 'last': 'hendrix'}
Функция получает простую текстовую информацию и помещает ее в более удоб- ную структуру данных, которая позволяет работать с информацией (помимо про- стого вывода). Строки 'jimi'
и 'hendrix'
теперь помечены как имя и фамилия.
Функцию можно легко расширить так, чтобы она принимала дополнительные значения: — второе имя, возраст, профессию или любую другую информацию о че- ловеке, которую вы хотите сохранить. Например, следующее изменение позволяет также сохранить возраст человека:
def build_person(first_name, last_name, age=''):
"""Возвращает словарь с информацией о человеке."""
person = {'first': first_name, 'last': last_name}
if age:
person['age'] = age return person musician = build_person('jimi', 'hendrix', age=27)
print(musician)
В определение функции добавляется новый необязательный параметр age
, кото- рому назначается пустое значение по умолчанию. Если вызов функции включает значение этого параметра, то значение сохраняется в словаре. Функция всегда сохраняет имя, но ее также можно модифицировать, чтобы она сохраняла любую необходимую информацию о человеке.

146 Глава 8 • Функции
Использование функции в цикле while
Функции могут использоваться со всеми структурами Python, уже известными вам. Например, используем функцию get_formatted_name()
в цикле while
, чтобы поприветствовать пользователей более официально. Первая версия программы, приветствующей пользователей по имени и фамилии, может выглядеть так:
greeter.py
def get_formatted_name(first_name, last_name):
"""Возвращает аккуратно отформатированное полное имя."""
full_name = first_name + ' ' + last_name return full_name.title()
# Бесконечный цикл!
while True:
 print("\nPlease tell me your name:")
f_name = input("First name: ")
l_name = input("Last name: ")
formatted_name = get_formatted_name(f_name, l_name)
print("\nHello, " + formatted_name + "!")
В этом примере используется простая версия get_formatted_name()
, без вторых имен. В цикле while
 имя и фамилия пользователя запрашиваются по отдель- ности.
Но у этого цикла while есть один недостаток: в нем не определено условие завер- шения. Где следует разместить условие завершения при запросе серии данных?
Пользователю нужно предоставить возможность выйти из цикла как можно рань- ше, так что в приглашении должен содержаться способ завершения. Команда break позволяет немедленно прервать цикл при запросе любого из компонентов:
def get_formatted_name(first_name, last_name):
"""Возвращает аккуратно отформатированное полное имя."""
full_name = first_name + ' ' + last_name return full_name.title()
while True:
print("\nPlease tell me your name:")
print("(enter 'q' at any time to quit)")
f_name = input("First name: ")
if f_name == 'q':
break l_name = input("Last name: ")
if l_name == 'q':
break formatted_name = get_formatted_name(f_name, l_name)
print("\nHello, " + formatted_name + "!")
В программу добавляется сообщение, которое объясняет пользователю, как за- вершить ввод данных, и при вводе признака завершения в любом из приглашений

Передача списка 147
цикл прерывается. Теперь программа будет приветствовать пользователя до тех пор, пока вместо имени или фамилии не будет введен символ 'q'
:
Please tell me your name:
(enter 'q' at any time to quit)
First name: eric
Last name: matthes
Hello, Eric Matthes!
Please tell me your name:
(enter 'q' at any time to quit)
First name: q
УПРАЖНЕНИЯ
8-6 . Названия городов: напишите функцию city_country(), которая получает название го- рода и страну . Функция должна возвращать строку в формате “Santiago, Chile” . Вызовите свою функцию по крайней мере для трех пар «город—страна» и выведите возвращенное значение .
8-7 . Альбом: напишите функцию make_album(), которая строит словарь с описанием му- зыкального альбома . Функция должна получать имя исполнителя и название альбома и возвращать словарь, содержащий эти два вида информации . Используйте функцию для создания трех словарей, представляющих разные альбомы . Выведите все возвраща- емые значения, чтобы показать, что информация правильно сохраняется во всех трех словарях .
Добавьте в make_album() дополнительный параметр для сохранения количества дорожек в альбоме . Если в строку вызова включено значение количества дорожек, добавьте это зна- чение в словарь альбома . Создайте как минимум один новый вызов функции с передачей количества дорожек в альбоме .
8-8 . Пользовательские альбомы: начните с программы из упражнения 8-7 . Напишите цикл while, в котором пользователь вводит исполнителя и название альбома . Затем в цикле вы- зывается функция make_album() для введенных пользователей и выводится созданный словарь . Не забудьте предусмотреть признак завершения в цикле while .
Передача списка
Часто при вызове функции удобно передать список — имен, чисел или более сложных объектов (например, словарей). При передаче списка функция получает прямой доступ ко всему его содержимому. Мы воспользуемся функциями для того, чтобы сделать работу со списком более эффективной.
Допустим, вы хотите вывести приветствие для каждого пользователя из списка.
В следующем примере список имен передается функции greet_users()
, которая выводит приветствие для каждого пользователя по отдельности:
greet_users.py
def greet_users(names):
"""Вывод простого приветствия для каждого пользователя в списке."""
for name in names:
msg = "Hello, " + name.title() + "!"
print(msg)

148 Глава 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)

1   ...   13   14   15   16   17   18   19   20   ...   53


написать администратору сайта