Изучаем Python — страница 21 из 61


Функция не обязана выводить результаты своей работы. Вместо этого она может обработать данные, а затем вернуть значение или набор сообщений. Значение, возвращаемое функцией, называется возвращаемым значением. Команда return передает значение из функции в строку, в которой эта функция была вызвана. Возвращаемые значения помогают переместить бульшую часть рутинной работы в вашей программе в функции, чтобы упростить основной код программы.

Возвращение простого значения


Рассмотрим функцию, которая получает имя и фамилию и возвращает аккуратно отформатированное полное имя:

formatted_name.py

(1) def get_formatted_name(first_name, last_name):

. ."""Возвращает аккуратно отформатированное полное имя."""

(2) . .full_name = first_name + ' ' + last_name

(3) . .return full_name.title()

(4)musician = get_formatted_name('jimi', 'hendrix')

print(musician)

Определение get_formatted_name() получает в параметрах имя и фамилию (1) . Функция объединяет эти два имени, добавляет между ними пробел и сохраняет результат в full_name (2). Значение full_name преобразуется в формат с начальной буквой верхнего регистра, а затем возвращается в точку вызова (3).

Вызывая функцию, которая возвращает значение, необходимо предоставить переменную, в которой должно храниться возвращаемое значение. В данном случае возвращаемое значение сохраняется в переменной musician (4). Результат содержит аккуратно отформатированное полное имя, построенное из имени и фамилии:

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)

Функция работает при получении имени, второго имени и фамилии. Она получает все три части имени, а затем строит из них строку. Функция добавляет пробелы там, где это уместно, и преобразует полное имя в формат с капитализацией:

John Lee Hooker

Однако вторые имена нужны не всегда, а в такой записи функция не будет работать, если при вызове ей передаются только имя и фамилия. Чтобы средний аргумент был необязательным, можно присвоить аргументу middle_name пустое значение по умолчанию; этот аргумент игнорируется, если пользователь не передал для него значение. Чтобы функция get_formatted_name() работала без второго имени, следует назначить для параметра middle_name пустую строку значением по умолчанию и переместить его в конец списка параметров:

(1) def get_formatted_name(first_name, last_name, middle_name=''):

. ."""Возвращает аккуратно отформатированное полное имя."""

(2) . .if middle_name:

. . . .full_name = first_name + ' ' + middle_name + ' ' + last_ name

(3) . .else:

. . . .full_name = first_name + ' ' + last_name

. .return full_name.title()


musician = get_formatted_name('jimi', 'hendrix')

print(musician)


(4)musician = get_formatted_name('john', 'hooker', 'lee')

print(musician)

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

В теле функции мы сначала проверяем, было ли задано второе имя. Python интерпретирует непустые строки как истинное значение, и, если при вызове задан аргумент второго имени, middle_name дает результат True (2). Если второе имя указано, то из имени, второго имени и фамилии строится полное имя. Затем имя преобразуется с капитализацией символов и возвращается в строку вызова функции, где оно сохраняется в переменной musician и выводится. Если второе имя не указано, то пустая строка не проходит проверку if и выполняет блок else (3). В этом случае полное имя строится только из имени и фамилии, и отформатированное имя возвращается в строку вызова, где оно сохраняется в переменной musician и выводится.

Вызов этой функции с именем и фамилией достаточно тривиален. Но при использовании второго имени придется проследить за тем, чтобы второе имя было последним из передаваемых аргументов. Это необходимо для правильного связывания позиционных аргументов в строке (4).

Обновленная версия этой функции подойдет как для людей, у которых задается только имя и фамилия, так и для людей со вторым именем:

Jimi Hendrix

John Lee Hooker

Необязательные значения позволяют функциям работать в максимально широком спектре сценариев использования без усложнения вызовов.

Возвращение словаря


Функция может вернуть любое значение, нужное вам, в том числе и более сложную структуру данных (например, список или словарь). Так, следующая функция получает части имени и возвращает словарь, представляющий человека:

person.py

def build_person(first_name, last_name):

. ."""Возвращает словарь с информацией о человеке."""

(1) . .person = {'first': first_name, 'last': last_name}

(2) . .return person


musician = build_person('jimi', 'hendrix')

(3)print(musician)

Функция build_person() получает имя и фамилию и сохраняет полученные значения в словаре в точке (1) . Значение first_name сохраняется с ключом 'first', а значение last_name — с ключом 'last'. Весь словарь с описанием человека возвращается в точке (2). Возвращаемое значение выводится в точке (3) с двумя исходными фрагментами текстовой информации, теперь хранящимися в словаре:

{'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, которому назначается пустое значение по умолчанию. Если вызов функции включает значение этого параметра, то значение сохраняется в словаре. Функция всегда сохраняет имя, но ее также можно модифицировать, чтобы она сохраняла любую необходимую информацию о человеке.

Использование функции в цикле 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:

(1) . .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 (1) имя и фамилия пользователя запрашиваются по отдельности.

Но у этого цикла 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 + "!")

В программу добавляется сообщение, которое объясняет пользователю, как завершить ввод данных, и при вводе признака завершения в любом из приглашений цикл прерывается. Теперь программа будет приветствовать пользователя до тех пор, пока вместо имени или фамилии не будет введен символ '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.

Передача списка