Возврат значений из функции. Оператор return
Функции могут передавать какие-либо данные из своих тел в основную ветку программы. Говорят, что функция возвращает значение. В большинстве языков программирования, в том числе Python, выход из функции и передача данных в то место, откуда она была вызвана, выполняется оператором return .
Если интерпретатор Питона, выполняя тело функции, встречает return , то он «забирает» значение, указанное после этой команды, и «уходит» из функции.
def cylinder(): r = float(input()) h = float(input()) # площадь боковой поверхности цилиндра: side = 2 * 3.14 * r * h # площадь одного основания цилиндра: circle = 3.14 * r**2 # полная площадь цилиндра: full = side + 2 * circle return full square = cylinder() print(square)
3 7 188.4
В данной программе в основную ветку из функции возвращается значение локальной переменной full . Не сама переменная, а ее значение, в данном случае – какое-либо число, полученное в результате вычисления площади цилиндра.
В основной ветке программы это значение присваивается глобальной переменной square . То есть выражение square = cylinder() выполняется так:
- Вызывается функция cylinder() .
- Из нее возвращается значение.
- Это значение присваивается переменной square .
Не обязательно присваивать результат переменной, его можно сразу вывести на экран:
. print(cylinder())
Здесь число, полученное из cylinder() , непосредственно передается функции print() . Если мы в программе просто напишем cylinder() , не присвоив полученные данные переменной или не передав их куда-либо дальше, то эти данные будут потеряны. Но синтаксической ошибки не будет.
В функции может быть несколько операторов return . Однако всегда выполняется только один из них. Тот, которого первым достигнет поток выполнения. Допустим, мы решили обработать исключение, возникающее на некорректный ввод. Пусть тогда в ветке except обработчика исключений происходит выход из функции без всяких вычислений и передачи значения:
def cylinder(): try: r = float(input()) h = float(input()) except ValueError: return side = 2 * 3.14 * r * h circle = 3.14 * r**2 full = side + 2 * circle return full print(cylinder())
Если попытаться вместо цифр ввести буквы, то сработает return , вложенный в except . Он завершит выполнение функции, так что все нижеследующие вычисления, в том числе return full , будут опущены. Пример выполнения:
r None
Но постойте! Что это за слово None , которое нам вернул «пустой» return ? Это ничего, такой объект – «ничто». Он принадлежит классу NoneType . До этого мы знали четыре типа данных, они же четыре класса: int , float , str , bool . Пришло время пятого.
Когда после return ничего не указывается, то по умолчанию считается, что там стоит объект None . При желании мы можете явно писать return None .
Более того. Ранее мы рассматривали функции, которые вроде бы не возвращали никакого значения, потому что в них не было оператора return . На самом деле возвращали, просто мы не обращали на него внимание, не присваивали никакой переменной и не выводили на экран. В Python всякая функция что-либо возвращает. Если в ней нет оператора return , то она возвращает None . То же самое, как если в ней имеется «пустой» return .
Возврат нескольких значений
В Питоне позволительно возвращать из функции несколько объектов, перечислив их через запятую после команды return :
def cylinder(): r = float(input()) h = float(input()) side = 2 * 3.14 * r * h circle = 3.14 * r ** 2 full = side + 2 * circle return side, full s_cyl, f_cyl = cylinder() print("Площадь боковой поверхности %.2f" % s_cyl) print("Полная площадь %.2f" % f_cyl)
Из функции cylinder() возвращаются два значения. Первое из них присваивается переменной s_cyl , второе – f_cyl . Возможность такого группового присвоения – особенность Python, обычно не характерная для других языков:
>>> a, b, c = 10, 15, 19 >>> a 10 >>> b 15 >>> c 19
Фокус здесь в том, что перечисление значений через запятую (например, 10, 15, 19 ) создает объект типа tuple . На русский переводится как «кортеж». Это разновидность структур данных, которые будут изучены позже.
Когда же кортеж присваивается сразу нескольким переменным, то происходит сопоставление его элементов соответствующим в очереди переменным. Это называется распаковкой.
Таким образом, когда из функции возвращается несколько значений, на самом деле из нее возвращается один объект класса tuple . Перед возвратом эти несколько значений упаковываются в кортеж. Если же после оператора return стоит только одна переменная или объект, то ее/его тип сохраняется как есть.
Распаковка не является обязательной. Будет работать и так:
… print(cylinder())
4 3 (75.36, 175.84)
На экран выводится кортеж, о чем говорят круглые скобки. Его также можно присвоить одной переменной, а потом вывести ее значение на экран.
Практическая работа
- Напишите программу, в которой вызывается функция, запрашивающая с ввода две строки и возвращающая в программу результат их конкатенации. Выведите результат на экран.
- Напишите функцию, которая считывает с клавиатуры числа и перемножает их до тех пор, пока не будет введен 0. Функция должна возвращать полученное произведение. Вызовите функцию и выведите на экран результат ее работы.
Примеры решения и дополнительные уроки в pdf-версии курса
X Скрыть Наверх
Python. Введение в программирование
Как сделать несколько return в одной функции в Python?
Функция в python может вернуть значение только один раз. Если нужно вернуть разные значения в зависимости от условий, то можно воспользоваться условной конструкцией if :
def function(): . if condition1: return result1 if condition2: return result2
Также можно вернуть несколько значений одновременно в виде кортежа:
def function(): . return result1, result2
Возврат нескольких значений из функции
Python позволяет вам возвращать из функции несколько значений.
Для этого необходимо вернуть структуру данных, содержащую эти несколько значений. Например, список количества миль, которые надо пробежать за неделю.
def miles_to_run(minimum_miles): week_1 = minimum_miles + 2 week_2 = minimum_miles + 4 week_3 = minimum_miles + 6 return [week_1, week_2, week_3] print(miles_to_run(2)) # result: [4, 6, 8]
Структура данных — контейнер, хранящий однотипные данные. Эти данные могут быть возвращены из функций. В этой статье мы узнаем, как возвращать несколько значений из структур вроде кортежа, списка и словаря.
Кортежи
Кортеж — упорядоченная, неизменяемая последовательность. То есть, значения внутри кортежа мы изменять не можем.
Мы можем использовать кортеж, например, для хранения информации о человеке (о его имени, возрасте, месте жительства).
nancy = ("Нэнси", 55, "Чикаго")
Пример функции, которая возвращает кортеж:
def person(): return "Боб", 32, "Бостон" print(person()) # result: ('Боб', 32, 'Бостон')
Заметьте, что в предложении return мы не использовали круглые скобки для возврата значения. Это потому, что кортеж можно вернуть, просто отделив каждый элемент запятой, как в нашем примере.
«Кортеж образуют запятые, а не круглые скобки» — так написано в документации. Но для создания пустых кортежей круглые скобки необходимы. Также это помогает избежать путаницы.
Пример функции, которая использует () для возврата кортежа:
def person(name, age): return (name, age) print(person("Генри", 5)) #result: ('Генри', 5)
Список
Список — упорядоченная, изменяемая последовательность. Элементы списка можно изменять.
Список с городами:
cities = ["Бостон", "Чикаго", "Джексонвилл"]
test_scores = [55, 99, 100, 68, 85, 78]
Взгляните на функцию ниже. Она возвращает список, содержащий десять чисел.
def ten_numbers(): numbers = [] for i in range(1, 11): numbers.append(i) return numbers print(ten_numbers()) #result: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Еще один пример. В этот раз мы передаем несколько аргументов в функцию.
def miles_ran(week_1, week_2, week_3, week_4): return [week_1, week_2, week_3, week_4] monthly_mileage = miles_ran(25, 30, 28, 40) print(monthly_mileage) #result: [25, 30, 28, 40]
Спутать кортеж со списком довольно просто. Все-таки обе структуры хранят несколько значений. Важно запомнить ключевые отличия:
- Кортежи изменять нельзя.
- Списки изменять можно.
Словари
Словарь — структура, в которой хранятся пары значений в виде «ключ-значение». Заключены эти значения в фигурные скобки <> . Каждому ключу соответствует свое значение.
Рассмотрим пример. В следующем словаре содержатся имена сотрудников. Имя сотрудника — ключ, его должность — значение.
employees =
Пример функции, возвращающей словарь в виде «ключ-значение».
def city_country(city, country): location = <> location[city] = country return location favorite_location = city_country(«Бостон», «США») print(favorite_location) # result:
В примере выше «Бостон» — ключ, а «США» — значение.
Мы проделали долгий путь… Подытожим — вы можете вернуть несколько значений из функции и существует несколько способов сделать это.
Функция возвращает несколько значений
Я нередко слышу от новичков, что функция может возвращать только одно значение, и что процедуры в Паскале возвращать значения не могут. Заблуждения — это обычное дело в начале изучения какого-нибудь предмета. Но чем быстрее вы начнёте от них избавляться, тем лучше. И сегодня я как раз помогу вам это сделать. Итак:
- Процедуры в Паскале могут возвращать значения
- Функции и процедуры могут возвращать несколько значений
А теперь рассмотрим несколько способов.
Используем запись
Не самый удобный способ, но во многих случаях его можно и нужно использовать. Функция при этом будет возвращать одно значение, но это значение будет иметь тип записи, а запись, как вы понимаете, может содержать в себе множество переменных разных типов. Пример:
type TCoord = record X, Y : Integer; end; //******************************************************************* // Способ 1: использование записи //******************************************************************* function GetCoordRec(Point : TCoord) : TCoord; begin Point.X := 10; Point.Y := 5; Result := Point; end;
Думаю, особых пояснений здесь не требуется. Использовать эту функцию в программе можно, например, так:
var Point : TCoord; begin //Способ 1 Point := GetCoordRec(Point); WriteLn('X, Y : ', Point.X, ', ', Point.Y); end.
Используем массив
Принцип действия тот же, что и при использовании записи. Отличие в том, что в записи могут быть переменные разных типов, а в массиве только однотипные. И сначала надо будет объявить новый тип для массива, потому что функция может возвращать только данные определённого типа, а массив сам по себе типом не является. То есть вот это не прокатит:
function GetCoordMas : array[1..2] of Integer;
и компилятор выдаст ошибку. Поэтому делать надо так:
type AInteger = array[1..2] of Integer; //******************************************************************* // Способ 2: использование массива //******************************************************************* function GetCoordMas : AInteger; begin Result[1] := 15; Result[2] := 16; end;
Это будет работать, и в программе можно использовать, например, так:
var A : AInteger; begin //Способ 2 A := GetCoordMas; WriteLn('X, Y : ', A[1], ', ', A[2]); end.
Используем var
Это самый простой способ вернуть из функции или процедуры любое количество значений любых типов. И в большинстве случаев использовать надо именно этот способ:
//******************************************************************* // Способ 3: использование var //******************************************************************* function GetCoordVar(var X : Integer) : Integer; begin X := 11; Result := 6; end;
Здесь я немного поизвращался. Но это для наглядности. Если в списке параметров функции или процедуры перед именем переменной указать слово var , то это будет означать, что через эту переменную будет не только передано значение в подпрограмму, но и получено значение из подпрограммы. Подробнее об этом здесь.
Используем указатели
Для новичков это самый сложный способ. Да и я в подавляющем большинстве случаев не вижу смысла его использовать. Но знать об этом надо, потому что многие стандартные функции, особенно системные и особенно в С++, используют именно его.
Суть его в том, чтобы передавать в подпрограмму не переменную, а её адрес. Тогда изменение данных в памяти, на которые указывает этот адрес, автоматически приведёт к изменению значений всех переменных, которые ссылаются на эту область в памяти.
type PInteger = ^Integer; //*************************************************************** // Способ 4: использование указателей //*************************************************************** procedure GetCoordP(x, y : PInteger); begin x^ := 100; y^ := 200; end;
Здесь тоже придётся объявить отдельный тип, потому что вот это не прокатит:
procedure GetCoordP(x, y : ^Integer);
Компилятор выдаст ошибку.
В программе использовать такую процедуру (или функцию) можно так:
Как вы понимаете, при работе с указателями надо выделять память перед её использованием и освобождать после использования. Вот здесь вы можете найти больше сведений об указателях.
На этом останавливаюсь. Основные мысли я изложил. При желании вы можете подключить воображение и придумать что-нибудь ещё. Ну и, разумеется, описанные выше способы можно комбинировать. Также скажу, что всё это в той или иной степени справедливо и для других языков программирования. Разумеется, с учётом их особенностей.
Подписывайтесь на новости, чтобы ничего не пропустить (ссылки под видео), а если что-то ещё не вполне понятно, то см. видео:
