How do I get a result (output) from a function? How can I use the result later?
How do I get the function to return x , in such a way that I can use it as the input for another function or use the variable within the body of a program? I tried using return and then using the x variable in another function, but I get a NameError that way.
For the specific case of communicating information between methods in the same class, it is often best to store the information in self . See Passing variables between methods in Python? for details.
4 Answers 4
You can use the return statement to return a value from a function, this does not make it so that the returned variable (value) becomes available in the scope of the caller. To use the value in the caller you can either use it directly in a statement or capture the value in a variable.
Here’s some code to demonstrate this:
![]()
Effectively, there are two ways: directly and indirectly.
The direct way is to return a value from the function, as you tried, and let the calling code use that value. This is normally what you want. The natural, simple, direct, explicit way to get information back from a function is to return it. Broadly speaking, the purpose of a function is to compute a value, and return signifies "this is the value we computed; we are done here".
Directly using return
The main trick here is that return returns a value, not a variable. So return x does not enable the calling code to use x after calling the function, and does not modify any existing value that x had in the context of the call. (That’s presumably why you got a NameError .)
After we use return in the function:
we need to write the calling code to use the return value:
The other key point here is that a call to a function is an expression, so we can use it the same way that we use, say, the result of an addition. Just as we may say result = ‘hello ‘ + ‘world’ , we may say result = foo() . After that, result is our own, local name for that string, and we can do whatever we want with it.
We can use the same name, x , if we want. Or we can use a different name. The calling code doesn’t have to know anything about how the function is written, or what names it uses for things. 1
We can use the value directly to call another function: for example, print(foo()) . 2 We can return the value directly: simply return ‘hello world’ , without assigning to x . (Again: we are returning a value, not a variable.)
The function can only return once each time it is called. return terminates the function — again, we just determined the result of the calculation, so there is no reason to calculate any further. If we want to return multiple pieces of information, therefore, we will need to come up with a single object (in Python, "value" and "object" are effectively synonyms; this doesn’t work out so well for some other languages.)
We can make a tuple right on the return line; or we can use a dictionary, a namedtuple (Python 2.6+), a types.simpleNamespace (Python 3.3+), a dataclass (Python 3.7+), or some other class (perhaps even one we write ourselves) to associate names with the values that are being returned; or we can accumulate values from a loop in a list; etc. etc. The possibilities are endless..
On the other hand, the function return s whether you like it or not (unless an exception is raised). If it reaches the end, it will implicitly return the special value None . You may or may not want to do it explicitly instead.
Indirect methods
Other than return ing the result back to the caller directly, we can communicate it by modifying some existing object that the caller knows about. There are many ways to do that, but they’re all variations on that same theme.
If you want the code to communicate information back this way, please just let it return None — don’t also use the return value for something meaningful. That’s how the built-in functionality works.
In order to modify that object, the called function also has to know about it, of course. That means, having a name for the object that can be looked up in a current scope. So, let’s go through those in order:
Local scope: Modifying a passed-in argument
If one of our parameters is mutable, we can just mutate it, and rely on the caller to examine the change. This is usually not a great idea, because it can be hard to reason about the code. It looks like:
If the value is an instance of our own class, we could also assign to an attribute:
Assigning to an attribute does not work for built-in types, including object ; and it might not work for some classes that explicitly prevent you from doing it.
Local scope: Modifying self , in a method
We already have an example of this above: setting self.value in the Test.__init__ code. This is a special case of modifying a passed-in argument; but it’s part of how classes work in Python, and something we’re expected to do. Normally, when we do this, the calling won’t actually check for changes to self — it will just use the modified object in the next step of the logic. That’s what makes it appropriate to write code this way: we’re still presenting an interface, so the caller doesn’t have to worry about the details.
In the example, calling add_word gave information back to the top-level code — but instead of looking for it, we just go ahead and call display . 3
Enclosing scope
This is a rare special case when using nested functions. There isn’t a lot to say here — it works the same way as with the global scope, just using the nonlocal keyword rather than global . 4
Global scope: Modifying a global
Generally speaking, it is a bad idea to change anything in the global scope after setting it up in the first place. It makes code harder to reason about, because anything that uses that global (aside from whatever was responsible for the change) now has a "hidden" source of input.
If you still want to do it, the syntax is straightforward:
Global scope: Assigning to a new or existing global
This is actually a special case of modifying a global. I don’t mean that assignment is a kind of modification (it isn’t). I mean that when you assign a global name, Python automatically updates a dict that represents the global namespace. You can get that dict with globals() , and you can modify that dict and it will actually impact what global variables exist. (I.e., the return from globals() is the dictionary itself, not a copy.) 5
But please don’t. That’s even worse of an idea than the previous one. If you really need to get the result from your function by assigning to a global variable, use the global keyword to tell Python that the name should be looked up in the global scope:
Global scope: Assigning to or modifying an attribute of the function itself
This is a rare special case, but now that you’ve seen the other examples, the theory should be clear. In Python, functions are mutable (i.e. you can set attributes on them); and if we define a function at top level, it’s in the global namespace. So this is really just modifying a global:
We shouldn’t really use this to send information to the caller. It has all the usual problems with globals, and it’s even harder to understand. But it can be useful to set a function’s attributes from within the function, in order for the function to remember something in between calls. (It’s similar to how methods remember things in between calls by modifying self .) The functools standard library does this, for example in the cache implementation.
Builtin scope
This doesn’t work. The builtin namespace doesn’t contain any mutable objects, and you can’t assign new builtin names (they’ll go into the global namespace instead).
Some approaches that don’t work in Python
Just calculating something before the function ends
In some other programming languages, there is some kind of hidden variable that automatically picks up the result of the last calculation, every time something is calculated; and if you reach the end of a function without return ing anything, it gets returned. That doesn’t work in Python. If you reach the end without return ing anything, your function returns None .
Assigning to the function’s name
In some other programming languages, you are allowed (or expected) to assign to a variable with the same name as the function; and at the end of the function, that value is returned. That still doesn’t work in Python. If you reach the end without return ing anything, your function still returns None .
It might seem like you can at least use the value that way, if you use the global keyword:
But this, of course, is just a special case of assigning to a global. And there’s a big problem with it — the same name can’t refer to two things at once. By doing this, the function replaced its own name. So it will fail next time:
Assigning to a parameter
Sometimes people expect to be able to assign to one of the function’s parameters, and have it affect a variable that was used for the corresponding argument. However, this does not work:
Just like how Python returns values, not variables, it also passes values, not variables. words is a local name; by definition the calling code doesn’t know anything about that namespace.
One of the working methods that we saw is to modify the passed-in list. That works because if the list itself changes, then it changes — it doesn’t matter what name is used for it, or what part of the code uses that name. However, assigning a new list to words does not cause the existing list to change. It just makes words start being a name for a different list.
1 At least, not for getting the value back. If you want to use keyword arguments, you need to know what the keyword names are. But generally, the point of functions is that they’re an abstraction; you only need to know about their interface, and you don’t need to think about what they’re doing internally.
2 In 2.x, print is a statement rather than a function, so this doesn’t make an example of calling another function directly. However, print foo() still works with 2.x’s print statement, and so does print(foo()) (in this case, the extra parentheses are just ordinary grouping parentheses). Aside from that, 2.7 (the last 2.x version) has been unsupported since the beginning of 2020 — which was nearly a 5 year extension of the normal schedule. But then, this question was originally asked in 2010.
3 Again: if the purpose of a method is to update the object, don’t also return a value. Some people like to return self so that you can "chain" method calls; but in Python this is considered poor style. If you want that kind of "fluent" interface, then instead of writing methods that update self , write methods that create a new, modified instance of the class.
4 Except, of course, that if we’re modifying a value rather than assigning, we don’t need either keyword.
5 There’s also a locals() that gives you a dict of local variables. However, this cannot be used to make new local variables — the behaviour is undefined in 2.x, and in 3.x the dict is created on the fly and assigning to it has no effect. Some of Python’s optimizations depend on the local variables for a function being known ahead of time.
Функции в Python
Функция — это именованный блок кода, к которому можно обратиться из любого места программы. У функции есть имя и список входных параметров, а также возвращаемое значение.
Функция позволяет использовать в программе один и тот же фрагмент кода несколько раз.
Oбъявление функции в Python выглядит так:
def function_name ( argument1 , argument2 , . ):
# код функции
# def — DEclare Function — «объявить функцию»
# function_name — имя функции
# (argument1, argument2, . ) — список аргументов, поступающих на вход функции при ее вызове
# тело функции — это весь код, который идет после двоеточия
# Объявление функции
def hello (name):
print ( ‘Hello, ‘ + name)
# Вызовы функции
hello ( ‘Max’ )
hello ( ‘Ivan’ )
hello ( ‘Alex’ )
hello ( ‘Kate’ )
# Вывод
>> Hello, Max
>> Hello, Ivan
>> Hello, Alex
>> Hello, Kate
Оператор return возвращает значение из функции.
Представьте себе обычный калькулятор. Вы вводите первое число, операцию и второе число. Калькулятор возвращает нам результат операции над этими числами. Всё просто, не так ли? Функции точно так же умеют возвращать значение с помощью специального оператора return.
# Объявление функции
def sum2 ( a , b ):
return a + b
# Вызовы функции
s1 = sum2 ( 10 , 2 )
s2 = sum2 ( 108 , 100 )
s3 = sum2 ( 3 , 1 )
print ( f ‘s1 =
print ( f ‘s2 =
print ( f ‘s3 =
>> s1 = 12
>> s2 = 208
>> s3 = 4
# Функция умножения двух чисел
def mult2 ( a , b ):
return a * b
# Вызовем нашу функцию
m1 = mult2 ( 10 , 2 )
m2 = mult2 ( 108 , 100 )
m3 = mult2 ( 3 , 1 )
print ( f ‘m1 =
print ( f ‘m2 =
print ( f ‘m3 =
>> m1 = 20
>> m2 = 10800
>> m3 = 3
Для параметров функции можно указывать значения по умолчанию. Это дает возможность вызывать функцию с меньшим числом параметров.
# Аргумент name по умолчанию равен ‘world’
def hello ( name = ‘world’ ):
print ( ‘Hello, ‘ + name)
hello ()
hello ( ‘Ivan’ )
>> Hello, world
>> Hello, Ivan
Примеры
# Написать функцию square(), вычисляющую квадрат числа.
def square ( number ):
return number * number # Возвращаем результат работы функции обратно в программу
a = square ( 2 )
print (a)
# Напишите функцию perimetr, вычисляющую периметр прямоугольника со сторонами a и b.
def perimetr ( a , b ):
return 2 * (a + b)
p = perimetr ( 4 , 3 )
print (p)
# Напишите функцию isEven, возвращающую True, если число четное, и False, если — нечетное.
def isEven ( x ):
return x % 2 == 0
print ( isEven ( 10 ))
print ( isEven ( 11 ))
# Напишите функцию amountList, которая возвращает сумму всех элементов списка.
def amountList ( lst ):
amount = 0
f or x in lst:
amount += x
return amount
print ( amountList ([ 1 , 2 , 3 ]))
mylist = [ 1 , 2 , 4 , 8 , 16 ]
s = amountList (mylist)
print ( f ‘Сумма списка ‘ )
>> 6
>> Сумма списка [ 1 , 2 , 4 , 8 , 16 ] равна 31
# Напишите функцию fib, которая возвращает n-ное число Фибоначчи.
# Последовательность Фибоначчи выглядит так: 1 1 2 3 5 8 13 21 34
def fib ( n ):
a, b = 0 , 1
if n == 0 : return 0
f or i in range ( 1 , n):
a, b = b, a + b
return b
print ( fib ( 2 ))
print ( fib ( 3 ))
print ( fib ( 4 ))
print ( fib ( 5 ))
print ( fib ( 10 ))
# Напишите функцию fact, вычисляющую значение факториала числа N.
# Факториал числа — это произведение всех чисел от 1 до N.
# Например, факториал числа 5 равен 120 (5! = 120).
def fact ( n ):
result = 1
while n > 1 :
result *= n
n -= 1
return result
print ( fact ( 2 ))
print ( fact ( 3 ))
print ( fact ( 4 ))
print ( fact ( 5 ))
Решение задач
Напишите функцию, которая получает в качестве аргумента радиус круга и находит его площадь.
# Не забудьте написать функцию circle.
print ( circle ( 4 ))
print ( circle ( 1 ))
Напишите функцию, которая возвращает True, если число делится на 3, и False, если — нет.
# Не забудьте написать функцию three.
print ( three ( 4 ))
print ( three ( 3 ))
3. Максимум в списке
Напишите функцию, которая возвращает максимальный элемент из переданного в нее списка.
# Напишите функцию maxList.
mylist = [ 1 , 3 , 2 ]
print ( maxList (mylist))
4. Сколько четных
Напишите функцию, которая возвращает количество четных элементов в списке.
# Напишите функцию evenCounter.
mylist = [ 1 , 10 , 2 , 4 , 6 ]
evens = evenCounter (mylist)
print (even)
Напишите функцию, которая возвращает список с уникальными (неповторяющихся) элементам.
# Напишите функцию unique.
mylist = [ 1 , 1 , 2 , 1 , 3 , 2 , 3 ]
print ( unique (mylist))
Функции в Python — синтаксис, аргументы, вызов, выход
Его можно вызывать в любом месте основной программы. Функции помогают избегать дублирования кода при многократном его использовании. А также имеют ряд других преимуществ, описанных ниже.
Синтаксис
♀️ Простой пример: Вы торгуете мёдом, и после каждой продажи вам нужно печатать чек. В нём должно быть указано: название фирмы, дата продажи, список наименований проданных товаров, их количество, цены, общая сумма, а также сакраментальная фраза "Спасибо за покупку!".
Если не пользоваться функциями, всё придётся прописывать вручную. В простейшем случае программа будет выглядеть так:
print("ООО Медовый Гексагон") print("Мёд липовый", end=" ") print(1, end="шт ") print(1250, end="р") print("\nCумма", 1250, end="р") print("\nСпасибо за покупку!")
А теперь представьте, что произойдёт, когда вы раскрутитесь, и покупатели станут приходить один за другим. В таком случае, чеки надо будет выдавать очень быстро. Но что делать, если вдруг нагрянет ваш любимый клиент и купит 10 сортов мёда в разных количествах? Далеко не все в очереди согласятся ждать, пока вы посчитаете общую сумму и внесёте её в чек.
Хорошо, что данный процесс можно легко оптимизировать с использованием функций.
def print_check(honey_positions): sum = 0 # переменная для накопления общей суммы print("ООО Медовый Гексагон\n") # в цикле будем выводить название, количество и цену for honey in honey_positions: name = honey[0] amount = honey[1] price = honey[2] print(f"
Встаёт резонный вопрос: где же обещанное упрощение и куда подевались товары? Как раз для этого, мы и будем описывать состав покупки не напрямую в функции, а в отдельном списке кортежей. Каждый кортеж состоит из трёх элементов: название товара, количество и цена.
# (название, количество, цена за штуку) honey_positions = [ ("Мёд липовый", 3, 1250), ("Мёд цветочный", 7, 1000), ("Мёд гречишный", 6, 1300), ("Донниковый мёд", 1, 1750), ("Малиновый мёд", 10, 2000), ]
Теперь этот список передадим в функцию как аргумент, и самостоятельно считать больше не придётся.
print_check(honey_positions) > ООО Медовый Гексагон Мёд липовый (3 шт.) — 1250 руб. Мёд цветочный (7 шт.) — 1000 руб. Мёд гречишный (6 шт.) — 1300 руб. Донниковый мёд (1 шт.) — 1750 руб. Малиновый мёд (10 шт.) — 2000 руб. Итого: 40300 руб. Спасибо за покупку!
Да, код стал более массивным. Однако теперь для печати чека вам не придётся самостоятельно вычислять итог. Достаточно лишь изменить количество и цену товаров в списке. Существенная экономия времени! Слава функциям!
Термины и определения
Ключевое слово def в начале функции сообщает интерпретатору о том, что следующий за ним код — есть её определение. Всё вместе — это объявление функции.
# объявим функцию my_function() def my_function(): # тело функции
Аргументы часто путают с параметрами:
- Параметр — это переменная, которой будет присваиваться входящее в функцию значение.
- Аргумент — само это значение, которое передается в функцию при её вызове.
Ключевая особенность функций — возможность возвращать значение
Для этого используется слово return . Предположим, вы часто умножаете числа. Вы не осведомлены заранее, целые они или вещественные, но хотите, чтобы результат был целым всегда. Решим задачу с помощью функции:
# она будет принимать два множителя, а возвращать их округленное # до целого числа произведение def int_multiple(a, b): product = a * b # возвращаем значение return int(product) print(int_multiple(341, 2.7)) > 920
☝️ Главная фишка возвращаемых значений в том, что их можно использовать в дальнейшем коде: присваивать переменным, совершать с ними разные операции и передавать как аргументы в другие функции.
# найдём квадратный корень из возврата функции int_multiple # во встроенную функцию sqrt() мы передали вызов int_multiple print(math.sqrt(int_multiple(44, 44))) > 44
Важность функций
Абстракция
Человек бежит, машина едет, корабль плывёт, а самолёт летит. Всё это — объекты реального мира, которые выполняют однотипные действия. В данном случае, они перемещаются во времени и пространстве. Мы можем абстрагироваться от их природы, и рассматривать эти объекты с точки зрения того, какое расстояние они преодолели, и сколько времени на это ушло.
Мы можем написать функцию, которая вычисляет скорость в каждом конкретном случае. Нам не важно, кто совершает движение: и для человека и для самолёта средняя скорость будет рассчитываться одинаково.
def calculate_speed(distance, time): return distance / time
Это простой пример и простая функция, но абстракции могут быть куда более сложными. И именно тогда раскрывается настоящая сила функций. Вместо того чтобы решать задачу для каждого конкретного случая, проще написать функцию, которая находит решение для целого ряда однотипных, в рамках применяемой абстракции, объектов. В случае сложных и длинных вычислений, это повлечёт за собой значительное сокращение объёмов кода, а значит и времени на его написание.
Возможность повторного использования
Функции были созданы ради возможности их многократного применения. Код без функций превратился бы в огромное нечитаемое полотно, на порядки превышающее по длине аналогичную программу с их использованием.
Например, при работе с массивами чисел, вам нужно часто их сортировать. Вместо того чтобы реализовать простой алгоритм сортировки (или использовать встроенную функцию), вам пришлось бы каждый раз перепечатывать тело этой или похожей функции:
# пузырьковая сортировка def bubble_sort(nums): for i in range(0, len(nums) — 1): for j in range(len(nums) — 1): if nums[j] > nums[j + 1]: nums[j], nums[j + 1] = nums[j + 1], nums[j] return nums
Всего 10 таких сортировок, и привет, лишние 50 строк кода.
Модульность
Разбитие больших и сложных процессов на простые составляющие — важная часть, как кодинга, так и реальной жизни. В повседневности мы занимаемся этим неосознанно. Когда убираемся в квартире, мы пылесосим, моем полы и окна, очищаем поверхности от пыли и наводим блеск на всё блестящее. Всё это — составляющие одного большого процесса под названием "уборка", но каждую из них также можно разбить на более простые подпроцессы.
В программировании модульность строится на использовании функций. Для каждой подзадачи — своя функция. Такая компоновка в разы улучшает читабельность кода и уменьшает сложность его дальнейшей поддержки.
Допустим, мы работаем с базой данных. Нам нужна программа, которая считывает значения из базы, обрабатывает их, выводит результат на экран, а затем записывает его обратно в базу.
Без применения модульности получится сплошная последовательность инструкций:
# Database operation program # Код для чтения данных из базы # . # . # Код для выполнения операций над данными # . # . # Код для вывода результата # . # . # Код для записи данных в базу # . # .
Но если вынести каждую операцию в отдельную функцию, то текст главной программы получится маленьким и аккуратным.
def read_from_db(): # Код для чтения данных из базы # . # . # . def operate_with_data(): # Код для выполнения операций над данными # . # . # . def print_result(): # Код для вывода результата # . # . # . def write_to_db(): # Код для записи данных в базу # . # . # . # код основной программы # Database operation program read_from_db() operate_with_data() print_result() write_to_db()
Это и называется модульностью.
Пространство имен
Концепция пространства имён расширяет понятие модульности. Однако цель — не облегчить читаемость, а избежать конфликтов в названиях переменных.
♀️ Пример из жизни: в ВУЗе учатся два человека с совпадающими ФИО. Их нужно как-то различать. Если сделать пространствами имён группы этих студентов, то проблема будет решена. В рамках своей группы ФИО этих студентов будут уникальными.
Объявление и вызов функций
def hello(): print('Adele is cute')
После того как мы это сделали, функцию можно вызвать в любой части программы, но ниже самого объявления.
# код выполняется последовательно, поэтому сейчас интерпретатор # не знает о существовании функции hello hello() def hello(): print('Adele is cute') > NameError: name 'hello' is not defined
Поэтому стоит лишь поменять объявление и вызов местами, и всё заработает:
def hello(): print('Adele is cute') hello() > Adele is cute
Область видимости функций
Рассмотрим подробнее области видимости:
Локальная (L)
Локальная область видимости находится внутри def :
def L(): # переменная i_am_local является локальной внутри L() i_am_local = 5
Область объемлющих функций (E)
Объявили функцию e() . Внутри неё объявили функцию inner_e() . Относительно inner_e() все переменные, объявленные в e() будут относиться к области объемлющих функций. Такие переменные являются нелокальными в inner_e() . Чтобы с ними взаимодействовать, нужно использовать ключевое слово nonlocal :
def e(): x = 5 def inner_e(): nonlocal x x = x + 1 return x return inner_e() print(e()) > 6
Глобальная (G)
Глобальная область видимости лежит за пределами всех def .
# G num = 42 def some_function(n): res = n + num return res print(some_function(1)) > 43
Аргументы
Позиционные
Вспомним, аргумент — это конкретное значение, которое передаётся в функцию. Аргументом может быть любой объект. Он может передаваться, как в литеральной форме, так и в виде переменной.
Значения в позиционных аргументах подставляются согласно позиции имён аргументов:
nums = [42, 11, 121, 13, 7] state = True # в данном примере # 1-я позиция "nums" -> parameter_1 # 2-я позиция "state" -> parameter_2 def test_params(parameter_1, parameter_2): pass # равнозначные варианты вызова функции test_params(nums, state) test_params([42, 11, 121, 13, 7], True)
Именованные
Пусть есть функция, принимающая три аргумента, а затем выводящая их на экран. Python позволяет явно задавать соответствия между значениями и именами аргументов.
def print_trio(a, b, c): print(a, b, c) print_trio(c=4, b=5, a=6) > 6 5 4
При вызове соответствие будет определяться по именам, а не по позициям аргументов.
Необязательные параметры (параметры по умолчанию)
Python позволяет делать отдельные параметры функции необязательными. Если при вызове значение такого аргумента не передается, то ему будет присвоено значение по умолчанию.
def not_necessary_arg(x='My', y='love'): print(x, y) # если не передавать в функцию никаких значений, она отработает со значениями по умолчанию not_necessary_arg() > My love # переданные значения заменяют собой значения по умолчанию not_necessary_arg(2, 1) > 2 1
Аргументы переменной длины (args, kwargs)
Когда заранее неизвестно, сколько конкретно аргументов будет передано в функцию, мы пользуемся аргументами переменной длины. Звёздочка "*" перед именем параметра сообщает интерпретатору о том, что количество позиционных аргументов будет переменным:
def infinity(*args): print(args) infinity(42, 12, 'test', [6, 5]) > (42, 12, 'test', [6, 5])
Переменная args составляет кортеж из переданных в функцию аргументов.
Функции в питоне могут также принимать и переменное количество именованных аргументов. В этом случае перед названием параметра ставится " ** ":
def named_infinity(**kwargs): print(kwargs) named_infinity(first='nothing', second='else', third='matters') >
Здесь kwargs уже заключает аргументы не в кортеж, а в словарь.
Передача по значению и по ссылке
В Python аргументы могут быть переданы, как по ссылке, так и по значению. Всё зависит от типа объекта.
Если объект неизменяемый , то он передаётся в функцию по значению. Неизменяемые объекты это:
- Числовые типы (int, float, complex).
- Строки (str).
- Кортежи (tuple).
Изменяемые объекты передаются в функцию по ссылке. Изменяемыми они называются потому что их содержимое можно менять, при этом ссылка на сам объект остается неизменной.
В Python изменяемые объекты это:
- Списки (list).
- Множества (set).
- Словари (dict).
Будьте внимательны при передаче изменяемых объектов. Одна из частых проблем новичков.
В функциональном программировании существует понятие "функциями с побочными эффектами" — когда функция в процессе своей работы изменяет значения глобальных переменных. По возможности, избегать таких функций.
Словарь в качестве аргументов (упаковка)
Передаваемые в функцию аргументы можно упаковать в словарь при помощи оператора "**":
def big_dict(**arguments): print(arguments) big_dict(key='value') >
Возвращаемые значения (return)
Что можно возвращать
Функции в Python способны возвращать любой тип объекта.
Распаковка возвращаемых значений
В Питоне поддерживается возврат функциями сразу несколько значений. Достаточно перечислить их через запятую после инструкции return . Возвращаемым типом будет кортеж ( tuple ), который можно распаковать в переменные.
def calculate(num1, num2): return num1 + num2, num1 — num2, num1 * num2 # для так называемой распаковки нескольких значений # их следует присвоить равному количеству аргументов res1, res2, res3 = calculate(7, 6) print(res1, res2, res3) > 13 1 42 print(type(calculate(7, 6))) <class 'tuple'>
☝️ Обратите внимание, что количество возвращаемых значение в кортеже должно совпадать с количеством переменных при распаковке. Иначе произойдет ошибка:
def calculate(num1, num2): return num1 + num2, num1 — num2 # для так называемой распаковки нескольких значений # их следует присвоить равному количеству аргументов res1, res2, res3 = calculate(7, 6) print(res1, res2, res3) > ValueError: not enough values to unpack (expected 3, got 2)
Пустая функция
Иногда разработчики оставляют реализацию на потом, и чтобы объявленная функция не генерировала ошибки из-за отсутствия тела, в качестве заглушки используется ключевое слово pass :
Чистые функции и побочные эффекты
Немного функционального программирования. Есть такие функции, которые при вызове меняют файлы и таблицы баз данных, отправляют данные на сервер или модифицируют глобальные переменные. Всё это — побочные эффекты.
У чистых функций побочных эффектов нет. Такие функции не изменяют глобальные переменные в ходе выполнения, не рассылают и не выводят на печать никакие данные, не касаются объектов, и так далее.
Чистые функции производят вычисления по заданным аргументам и возвращают зависящий только от них самих результат.
Lambda функции
Кроме инструкции def в питоне можно создавать объекты функций в виде выражений. Так называемые анонимные функции создаются с помощью инструкции lambda . Чаще всего их применяют для получения встроенной функции или же для отложенного выполнения фрагмента программного кода.
lambda_test = lambda a, b: pow(a, b) print(lambda_test(2, 4)) > 16
Docstring
Документировать код — особое искусство. Оно существует параллельно с разработкой и сопоставимо с ней по важности. Поэтому нередко документации в программе больше, чем самого кода.
Когда над проектом работает большая команда, а может и не одна, да и еще и много лёт подряд, то значение и важность документации возрастают прямо пропорционально.
# Функции
Функция — блок кода для выполнения определенной задачи, который можно использовать многократно в разных частях программы. Существует множество встроенных в Python готовых функций. Некоторые вы уже применяли ранее: print() , str() , int() , float() , len() .
Создание функции называется определение. Оно начинается с ключевого слова def (от англ. definition, «определение»), затем идут имя функции, её аргументы, или параметры в круглых скобках и двоеточие. Начиная со следующей строки, с отступом в 4 пробела от начала, записывают тело функции — код, который она выполняет. Обращение к функции называется вызов функции. Функция вызывается по имени, при вызове ей передают аргументы, с которыми она должна что-то сделать.
Напишем приветствие как функцию:
Создали функцию с именем say_hello (англ. say hello, "поздороваться"). В любом месте программы при вызове say_hello() будет выводиться на экран приветствие с текстом, зависящим от аргумента current_hour (англ. current hour , "текущий час").
# Упражнения
- На основе заготовленного кода напишите функцию print_friends_count() для вывода количества друзей. Аргументом сделайте friends_count . Вызовите эту функцию не менее трёх раз с разными аргументами. Значениями friends_count могут быть любые натуральные числа.
- Напишите цикл для запусков print_friends_count() c аргументами от 1 до 10. Проследите изменения выведенных надписей.
# Упражнения tkinter
Напишите оконное приложение выводящее список количества друзей.
Напишите оконное приложение с полем ввода количества друзей. Кнопкой при нажатии на которую выводится сообщение о количестве друзей.
# Аргументы функции
В Python аргументам функций может быть присвоено значение по умолчанию. Оно подставляется, когда при вызове функции вы не оставляете насчёт аргументов никаких инструкций.
Функция say_hello() принимает два аргумента — current_hour и name (англ. name, "имя"), которому задано значение по умолчанию. При вызове только с одним аргументом current_hour значением второго аргумента name станет пустая строка.
При вызове функции можно явно указывать, какому аргументу какое значение соответствует. В таком случае порядок следования аргументов в скобках роли не играет.
# Упражнения
Допишите код функции print_friends_count() , добавьте аргумент name со значением по умолчанию. Если вы при вызове передаёте функции имя, она должна вывести на экран строку вида '<имя>, у тебя N друзей' , если нет — тогда просто 'У тебя N друзей' .
Анфиса может анализировать списки. Например, подсчитывать дни, когда в вашем городе или в городах ваших друзей стояла хорошая погода.
Есть списки средних дневных температур в Москве за май 2017 и 2018 годов. Создайте функцию comfort_count(temperatures) для подсчёта в переданном списке комфортных дней — дней с температурой воздуха от 22 до 26 градусов включительно.
Функция в результате работы должна вывести на экран строку 'Количество комфортных дней в этом месяце: N' , где N — результат подсчёта в цикле с условием. Сначала посчитайте приятные дни в мае 2017-го года, а потом — в мае 2018-го.
# Разбиение на функции
В больших проектах, написанных на Python, принято выносить весь повторяющийся код в отдельные функции перед телом основной программы. Посмотрим на пример:
Функция say_hello() содержит основную логику, а runner() (от англ. run, "запускать") выполняет роль управляющего механизма. Такое разделение придаёт коду программы аккуратный внешний вид, делает его более выразительным, упрощает чтение.
# Упражнения
- Подготовьте код Виты к использованию на сервере.
- Напишите функцию process_query() (англ. process query, «обработать запрос»). Перенесите в неё весь код из тела основной программы. Эта функция будет принимать на вход запросы пользователя и выдавать ответ на них. Пока она может обработать всего один запрос — сообщить количество друзей.
- Добавьте вызов функции process_query() в тело основной программы.
- На серверы приходит множество запросов — от разных пользователей или от других серверов. Измените функцию process_query() (обработчик запроса), чтобы она поддерживала несколько разных запросов, а не только один.
- Добавьте аргумент query в функцию process_query() . Этот аргумент будет сообщать, какой именно запрос необходимо обработать.
- В начало функции process_query() добавьте проверку значения переменной query: если значение равно 'Сколько у меня друзей?' — выведите ответ на этот вопрос, как в предыдущем задании;
- в противном случае — выведите '<неизвестный запрос>'. Добавьте вызов process_query('Сколько у меня друзей?') в основное тело программы. Добавьте ещё один вызов process_query('Как меня зовут?') в основное тело программы.
- Доработайте программу.
- Добавьте в функцию process_query() обработку ещё одного запроса 'Кто все мои друзья?'. В ответ нужно выводить на экран Твои друзья: <список_друзей>, где <список_друзей>— строка, состоящая из списка друзей, разделённых запятой и пробелом.
- Добавьте вызов process_query('Кто все мои друзья?') в тело основной программы.
# Возврат значений из функции
Пока что все наши функции печатали результаты своей работы на экран. Но обычно задача функции не сводится к выступлениям в печати. Как правило, это код, производящий специальные вычисления. Он не выводит результаты на экран, а возвращает их как значения. Значение вернётся в вызывающий код, и там будет использовано. Например, сохранено в переменной. Если программе нужно, к примеру, несколько раз посчитать одно и то же, эти вычисления поручают особым функциям:
Ключевое слово return (англ. «возвращать») указывает, какое значение функция вернёт основному коду.
# Упражнения
- Доработаем программу подсчёта комфортных дней в мае.
- Измените функцию comfort_count() , чтобы она не печатала количество комфортных дней, а возвращала.
- Чтобы увидеть результат выполнения функции, напечатайте его в основном коде командой print(comfort_count(may_2017)) .
# Вызов функции из функции
Функцию можно вызвать не только из основного кода, но и из другой функции.
Хорошая привычка — выделять вычисления и вывод в отдельные функции, чтобы печать результатов не была разбросана по всему коду.
Если бы мы ошиблись и забыли вернуть строку text из функции show_info(), то вывод получился бы странный:
Что такое None здесь? Это специальное значение в Python, и оно обозначает. ничего (англ. none, "ничто"). Если значение какой-нибудь переменной равно None , обычно это значит, что она не определена, не имеет никакого значения. Функция runner() печатает результаты вызовов функции show_info() . Так как в ней нет return , то она ничего не возвращает, и print() печатает это самое ничего.