Как вызвать функцию в питоне. Интерактивный учебник языка Python. Именные функции, инструкция def

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

Но постойте! Что это за слово 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 sCyl, fCyl = cylinder() print ("Площадь боковой поверхности %.2f" % sCyl) print ("Полная площадь %.2f" % fCyl)

Из функции cylinder() возвращаются два значения. Первое из них присваивается переменной sCyl , второе – fCyl . Возможность такого группового присвоения – особенность 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 )

На экран выводится кортеж, о чем говорят круглые скобки. Его также можно присвоить одной переменной, а потом вывести ее значение на экран.

5 августа 2008 в 16:14

Основы Python - кратко. Часть 5. Определение функций, основы.

  • Python

Начав писать главу про ООП, понял что совсем забыл освятить такой большой и нужный раздел Пайтона как функции. Тема это большая и обширная, потому, чтобы не сильно растягивать паузу между уроками, решил разделить ее на 2 части. Сначала расскажу основы, потом уже углубленные особенности Пайтоновского функциестроения.

Функции в Пайтоне объявляются не просто, а очень просто. Вот пример самой простой:

Def empty_func(): pass
Начинается объявление с ключевого слова def, что как не сложно догадаться является сокращением от define. После него идет имя функции. После имени в круглых скобках задается список параметров, в данном случае отсутствующих.
Тело функции пишется с отступом со следующей строки. учтите, что в Пайтоне функции с пустым телом запрещены, потому в качестве тела приведенной выше функции используется «пустой оператор» pass.
Теперь рассмотрим пример посерьезнее.

Def safe_div(x, y): """Do a safe division:-) for fun and profit""" if y != 0: z = x / y print z return z else: print "Yippie-kay-yay, motherf___er!"
В этом примере есть несколько нововведений. первое, что бросается в глаза - это строка документации (docstring), идущая сразу после тела функции.
Обычно эта строка занимает не одну строку исходного текста (простите за каламбур) и потому задается в тройных кавычках. Она предназначена для описания функции, ее предназначения, параметров и т.п. Все хорошие ИДЕ умеют с этой строкой работать. Получить к ней доступ можно и из самой программы, используя свойство __doc__:

Print safe_div.__doc__
Этим свойством (да, да, именно свойством, в Пайтоне даже функции на самом деле - классы) удобно пользоваться во время сеансов работы интерактивной консоли.
>>> from ftplib import FTP >>> print FTP.__doc__ An FTP client class. To create a connection, call the class using these argument: host, user, passwd, acct These are all strings, and have default value "". Then use self.connect() with optional host and port argument. # дальнейшее почикано мною:-)
Вернемся к нашей исходной функции. Суть ее очень проста, она принимает 2 параметра: х и у. Если у не равен 0, она делит х на у, выводит результат на экран и возвращает свое частное в виде результата. Результат функции возвращают с помощью команды return. Благодаря механизму кортежей, описанному в прошлом уроке, функции в Пайтоне могут возвращать одновременно множество объектов.
Если же делитель все-таки равен нулю, функция выводит сообщение об ошибке. Неверно было бы предположить что в этом случае функция ничего не вернет. Правильнее будет сказать что функция вернет «ничего»:) Иначе говоря, если в функции отсутствует оператор return, или же он вызван без параметров, то функция возвращает специальное значение None. В этом легко убедиться вызвав что-то типа print safe_div(10, 0).

Вот пример слегка посложнее, он взят из доклада-презентации Гвидо ван Россума.

Def gcd(a, b): "Нахождение НОД" while a != 0: a,b = b%a,a # параллельное определение return b
Данная функция находит наибольший общий делитель двух чисел.

В общем, следует учитывать, что параметры в функции Пайтоном передаются по ссылке. Еще одним, возможно нетривиальным фактом к которому придется привыкать - является тот факт что сами функции являются значением, которое можно присваивать. Если воспользоваться нашей функцией safe_div для дальнейших экспериментов, то можно написать следующий код.

Mystic_function = safe_div print mystic_function(10, 4)
Вот на этот раз и все, «за бортом» осталось еще много аспектов определения функций в Пайтоне, которые будут освещены в следующий раз.

Упражнения для проверки.
1. На основе существующей функции нахождения НОД, напишите функцию поиска НОК двух чисел.
2. Напишите подпрограмму табулирования функции, переданной в качестве аргумента. Так же аргументами задается начальное, конечное значение и шаг табуляции.

PS кстати, каков оптимальный объем «урока»? Что лучше - реже выходящие большие главы, или «лучше меньше да чаще».

Существует большое количество публикаций, посвящённых реализациям концепций функционального программирования на языке Python, но большая часть этих материалов написана одним автором - Девидом Мертцом (David Mertz). Кроме того, многие из этих статей уже устарели и разнесены по различным сетевым ресурсам. В этой статье мы попробуем снова обратиться к этой теме, чтобы освежить и упорядочить доступную информацию, особенно учитывая большие различия, имеющиеся между версиями Python линии 2 и линии 3.

Функции в Python

Функции в Python определяются 2-мя способами: через определение def или через анонимное описание lambda . Оба этих способа определения доступны, в той или иной степени, и в некоторых других языках программирования. Особенностью Python является то, что функция является таким же именованным объектом, как и любой другой объект некоторого типа данных, скажем, как целочисленная переменная. В листинге 1 представлен простейший пример (файл func.py из архива python_functional.tgz

Листинг 1. Определения функций
#!/usr/bin/python # -*- coding: utf-8 -*- import sys def show(fun, arg): print("{} : {}".format(type(fun), fun)) print("arg={} => fun(arg)={}".format(arg, fun(arg))) if len(sys.argv) > 1: n = float(sys.argv[ 1 ]) else: n = float(input("число?: ")) def pow3(n): # 1-е определение функции return n * n * n show(pow3, n) pow3 = lambda n: n * n * n # 2-е определение функции с тем же именем show(pow3, n) show((lambda n: n * n * n), n) # 3-е, использование анонимного описание функции

При вызове всех трёх объектов-функций мы получим один и тот же результат:

$ python func.py 1.3 : arg=1.3 => fun(arg)=2.197 : at 0xb7662bc4> arg=1.3 => fun(arg)=2.197 : at 0xb7662844> arg=1.3 => fun(arg)=2.197

Ещё более отчётливо это проявляется в Python версии 3, в которой всё является классами (в том числе, и целочисленная переменная), а функции являются объектами программы, принадлежащими к классу function :

$ python3 func.py 1.3 : arg=1.3 => fun(arg)=2.1970000000000005 : at 0xb745432c> arg=1.3 => fun(arg)=2.1970000000000005 : at 0xb74542ec> arg=1.3 => fun(arg)=2.1970000000000005

Примечание . Существуют ещё 2 типа объектов, допускающих функциональный вызов - функциональный метод класса и функтор, о которых мы поговорим позже.

Если функциональные объекты Python являются такими же объектами, как и другие объекты данных, значит, с ними можно и делать всё то, что можно делать с любыми данными:

  • динамически изменять в ходе выполнения;
  • встраивать в более сложные структуры данных (коллекции);
  • передавать в качестве параметров и возвращаемых значений и т.д.

На этом (манипуляции с функциональными объектами как с объектами данных) и базируется функциональное программирование. Python, конечно, не является настоящим языком функционального программирования, так, для полностью функционального программирования существуют специальные языки: Lisp, Planner, а из более свежих: Scala, Haskell. Ocaml, ... Но в Python можно "встраивать" приёмы функционального программирования в общий поток императивного (командного) кода, например, использовать методы, заимствованные из полноценных функциональных языков. Т.е. "сворачивать" отдельные фрагменты императивного кода (иногда достаточно большого объёма) в функциональные выражения.

Временами спрашивают: «В чём преимущества функционального стиля написания отдельных фрагментов для программиста?». Основным преимуществом функционального программирования является то, что после однократной отладки такого фрагмента в нём при последующем многократном использовании не возникнут ошибки за счёт побочных эффектов, связанных с присвоениями и конфликтом имён.

Достаточно часто при программировании на Python используют типичные конструкции из области функционального программирования, например:

print ([ (x,y) for x in (1, 2, 3, 4, 5) \ for y in (20, 15, 10) \ if x * y > 25 and x + y < 25 ])

В результате запуска получаем:

$ python funcp.py [(2,20), (2,15), (3,20), (3,15), (3,10), (4,20), (4,15), (4,10), (5,15), (5,10)]

Функции как объекты

Создавая объект функции оператором lambda , как было показано в листинге 1, можно привязать созданный функциональный объект к имени pow3 в точности так же, как можно было бы привязать к этому имени число 123 или строку "Hello!" . Этот пример подтверждает статус функций как объектов первого класса в Python. Функция в Python - это всего лишь ещё одно значение, с которым можно что-то сделать.

Наиболее частое действие, выполняемое с функциональными объектами первого класса, - это передача их во встроенные функции высшего порядка: map() , reduce() и filter() . Каждая из этих функций принимает объект функции в качестве своего первого аргумента.

  • map() применяет переданную функцию к каждому элементу в переданном списке (списках) и возвращает список результатов (той же размерности, что и входной);
  • reduce() применяет переданную функцию к каждому значению в списке и ко внутреннему накопителю результата, например, reduce(lambda n,m: n * m, range(1, 10)) означает 10! (факториал);
  • filter() применяет переданную функцию к каждому элементу списка и возвращает список тех элементов исходного списка, для которых переданная функция вернула значение истинности.

Комбинируя эти три функции, можно реализовать неожиданно широкий диапазон операций потока управления, не прибегая к императивным утверждениям, а используя лишь выражения в функциональном стиле, как показано в листинге 2 (файл funcH.py из архива python_functional.tgz

Листинг 2. Функции высших порядков Python
#!/usr/bin/python # -*- coding: utf-8 -*- import sys def input_arg(): global arg arg = (lambda: (len(sys.argv) > 1 and int(sys.argv[ 1 ])) or \ int(input("число?: ")))() return arg print("аргумент = {}".format(input_arg())) print(list(map(lambda x: x + 1, range(arg)))) print(list(filter(lambda x: x > 4, range(arg)))) import functools print("{}! = {}".format(arg, functools.reduce(lambda x, y: x * y, range(1, arg))))

Примечание. Этот код несколько усложнён по сравнению с предыдущим примером из-за следующих аспектов, связанных с совместимостью Python версий 2 и 3:

  • Функция reduce() , объявленная как встроенная в Python 2, в Python 3 была вынесена в модуль functools и её прямой вызов по имени вызовет исключение NameError , поэтому для корректной работы вызов должен быть оформлен как в примере или включать строку: from functools import *
  • Функции map() и filter() в Python 3 возвращают не список (что уже показывалось при обсуждении различий версий), а объекты-итераторы вида:

Для получения всего списка значений для них вызывается функция list() .

Поэтому такой код сможет работать в обеих версиях Python:

$ python3 funcH.py 7 аргумент = 7 7! = 720

Если переносимость кода между различными версиями не требуется, то подобные фрагменты можно исключить, что позволит несколько упростить код.

Рекурсия

В функциональном программировании рекурсия является основным механизмом, аналогично циклам в итеративном программировании.

В некоторых обсуждениях по Python неоднократно приходилось встречаться с заявлениями, что в Python глубина рекурсии ограничена "аппаратно", и поэтому некоторые действия реализовать невозможно в принципе. В интерпретаторе Python действительно по умолчанию установлено ограничение глубины рекурсии, равным 1000, но это численный параметр, который всегда можно переустановить, как показано в листинге 3 (полный код примера можно найти в файле fact2.py из архива python_functional.tgz

Листинг 3. Вычисление факториала с произвольной глубиной рекурсии
#!/usr/bin/python # -*- coding: utf-8 -*- import sys arg = lambda: (len(sys.argv) > 1 and int(sys.argv[ 1 ])) or \ int(input("число?: ")) factorial = lambda x: ((x == 1) and 1) or x * factorial(x - 1) n = arg() m = sys.getrecursionlimit() if n >= m - 1: sys.setrecursionlimit(n + 2) print("глубина рекурсии превышает установленную в системе {}, переустановлено в {}".\ format(m, sys.getrecursionlimit())) print("n={} => n!={}".format(n, factorial(n))) if sys.getrecursionlimit() > m: print("глубина рекурсии восстановлена в {}".format(m)) sys.setrecursionlimit(m)

Вот как выглядит исполнение этого примера в Python 3 и в Python2 (правда на самом деле полученное число вряд ли поместится на один экран терминала консоли):

$ python3 fact2.py 1001 глубина рекурсии превышает установленную в системе 1000, переустановлено в 1003 n=1001 => n!=4027.................................................0000000000000 глубина рекурсии восстановлена в 1000

Несколько простейших примеров

Выполним несколько простейших трансформаций привычного императивного кода (командного, операторного) для превращения его отдельных фрагментов в функциональные. Сначала заменим операторы ветвления логическими условиями, которые за счёт "отложенных" (lazy, ленивых) вычислений позволяют управлять выполнением или невыполнением отдельных ветвей кода. Так, императивная конструкция:

if <условие>: <выражение 1> else: <выражение 2>

Полностью эквивалентна следующему функциональному фрагменту (за счёт "отложенных" возможностей логических операторов and и or ):

# функция без параметров: lambda: (<условие> and <выражение 1>) or (<выражение 2>)

В качестве примера снова используем вычисление факториала. В листинге 4 приведен функциональный код для вычисления факториала (файл fact1.py в архиве python_functional.tgz в разделе "Материалы для скачивания"):

Листинг 4. Операторное (императивное) определение факториала
#!/usr/bin/python # -*- coding: utf-8 -*- import sys def factorial(n): if n == 1: return 1 else: return n * factorial(n - 1) if len(sys.argv) > 1: n = int(sys.argv[ 1 ]) else: n = int(input("число?: ")) print("n={} => n!={}".format(n, factorial(n)))

Аргумент для вычисления извлекается из значения параметра командной строки (если он есть) или вводится с терминала. Первый вариант изменения, показанный выше, уже применяется в листинге 2, где на функциональные выражения были заменены:

  • определение функции факториала: factorial = lambda x: ((x == 1) and 1) or x * factorial(x - 1)
  • запрос на ввод значения аргумента с консоли терминала: arg = lambda: (len(sys.argv) > 1 and int(sys.argv[ 1 ])) or \ int(input("число?: ")) n = arg()

В файле fact3.py появляется ещё одно определение функции, сделанное через функцию высшего порядка reduсe() :

factorial = factorial = lambda z: reduce(lambda x, y: x * y, range(1, z + 1))

Здесь же мы упростим также и выражение для n , сведя его к однократному вызову анонимной (не именованной) функции:

n = (lambda: (len(sys.argv) > 1 and int(sys.argv[ 1 ])) or \ int(input("число?: ")))()

Наконец, можно заметить, что присвоение значения переменной n требуется только для её использования в вызове print() для вывода этого значения. Если мы откажемся и от этого ограничения, то всё приложение выродится в один функциональный оператор (см. файл fact4.py в архиве python_functional.tgz в разделе "Материалы для скачивания"):

from sys import * from functools import reduce print("вычисленный факториал = {}".format(\ (lambda z: reduce(lambda x, y: x * y, range(1, z + 1))) \ ((lambda: (len(argv) > 1 and int(argv[ 1 ])) or \ int(input("число?: ")))())))

Этот единственный вызов внутри функции print() и представляет всё приложение в его функциональном варианте:

$ python3 fact4.py число?: 5 вычисленный факториал = 120

Читается ли этот код (файл fact4.py) лучше, чем императивная запись (файл fact1.py)? Скорее нет, чем да. В чём же тогда его достоинство? В том, что при любых изменениях окружающего его кода, нормальная работа этого фрагмента сохранится, так как отсутствует риск побочных эффектов из-за изменения значений используемых переменных.

Функции высших порядков

При функциональном стиле программирования стандартной практикой является динамическая генерация функционального объекта в процессе исполнения кода, с его последующим вызовом в том же коде. Существует целый ряд областей, где подобная техника может оказаться полезной.

Замыкание

Одно из интересных понятий функционального программирования - это замыкания (closure). Эта идея оказалась настолько заманчивой для многих разработчиков, что была реализована даже в некоторых нефункциональных языках программирования (Perl). Девид Мертц приводит следующее определение замыкания: "Замыкание - это процедура вместе с привязанной к ней совокупностью данных" (в противовес объектам в объектном программировании, как: "данные вместе с привязанным к ним совокупностью процедур").

Смысл замыкания состоит в том, что определение функции "замораживает" окружающий её контекст на момент определения . Это может делаться различными способами, например, за счёт параметризации создания функции, как показано в листинге 5 (файл clos1.py в архиве python_functional.tgz в разделе "Материалы для скачивания"):

Листинг 5. Создание замыкания
# -*- coding: utf-8 -*- def multiplier(n): # multiplier возвращает функцию умножения на n def mul(k): return n * k return mul mul3 = multiplier(3) # mul3 - функция, умножающая на 3 print(mul3(3), mul3(5))

Вот как срабатывает такая динамически определённая функция:

$ python clos1.py (9, 15) $ python3 clos1.py 9 15

Другой способ создания замыкания - это использование значения параметра по умолчанию в точке определения функции, как показано в листинге 6 (файл clos3.py из архива python_functional.tgz в разделе "Материалы для скачивания"):

Листинг 6. Другой способ создания замыкания
n = 3 def mult(k, mul = n): return mul * k n = 7 print(mult(3)) n = 13 print(mult(5)) n = 10 mult = lambda k, mul=n: mul * k print(mult(3))

Никакие последующие присвоения значений параметру по умолчанию не приведут к изменению ранее определённой функции, но сама функция может быть переопределена:

$ python clos3.py 9 15 30

Частичное применение функции

Частичное применение функции предполагает на основе функции N переменных определение новой функции с меньшим числом переменных M < N , при этом остальные N - M переменных получают фиксированные "замороженные" значения (используется модуль functools ). Подобный пример будет рассмотрен ниже.

Функтор

Функтор - это не функция, а объект класса, в котором определён метод с именем __call__() . При этом, для экземпляра такого объекта может применяться вызов, точно так же, как это происходит для функций. В листинге 7 (файл part.py из архива python_functional.tgz в разделе "Материалы для скачивания") демонстрируется использование замыкания, частичного определения функции и функтора, приводящих к получению одного и того же результата.

Листинг 7. Сравнение замыкания, частичного определения и функтора
# -*- coding: utf-8 -*- def multiplier(n): # замыкания - closure def mul(k): return n * k return mul mul3 = multiplier(3) from functools import partial def mulPart(a, b): # частичное применение функции return a * b par3 = partial(mulPart, 3) class mulFunctor: # эквивалентный функтор def __init__(self, val1): self.val1 = val1 def __call__(self, val2): return self.val1 * val2 fun3 = mulFunctor(3) print("{} . {} . {}".format(mul3(5), par3(5), fun3(5)))

Вызов всех трёх конструкций для аргумента, равного 5, приведёт к получению одинакового результата, хотя при этом и будут использоваться абсолютно разные механизмы:

$ python part.py 15 . 15 . 15

Карринг

Карринг (или каррирование, curring) - преобразование функции от многих переменных в функцию, берущую свои аргументы по одному.

Примечание . Это преобразование было введено М. Шейнфинкелем и Г. Фреге и получило своё название в честь математика Хаскелла Карри, в честь которого также назван и язык программирования Haskell.

Карринг не относится к уникальным особенностям функционального программирования, так карринговое преобразование может быть записано, например, и на языках Perl или C++. Оператор каррирования даже встроен в некоторые языки программирования (ML, Haskell), что позволяет многоместные функции приводить к каррированному представлению. Но все языки, поддерживающие замыкания, позволяют записывать каррированные функции, и Python не является исключением в этом плане.

В листинге 8 представлен простейший пример с использованием карринга (файл curry1.py в архиве python_functional.tgz в разделе "Материалы для скачивания"):

Листинг 8. Карринг
# -*- coding: utf-8 -*- def spam(x, y): print("param1={}, param2={}".format(x, y)) spam1 = lambda x: lambda y: spam(x, y) def spam2(x) : def new_spam(y) : return spam(x, y) return new_spam spam1(2)(3) # карринг spam2(2)(3)

Вот как выглядят исполнение этих вызовов:

$ python curry1.py param1=2, param2=3 param1=2, param2=3

Заключение

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

В следующей статье мы обсудим вопросы организации параллельного исполнения кода в среде Python.

Именные функции, инструкция def

Функция в python - объект, принимающий аргументы и возвращающий значение. Обычно функция определяется с помощью инструкции def.

Определим простейшую функцию:

Инструкция return говорит, что нужно вернуть значение. В нашем случае функция возвращает сумму x и y.

Теперь мы ее можем вызвать:

>>> add(1, 10)

>>> add("abc", "def")

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

>>> def newfunc(n):

Def myfunc(x):

Return x + n

Return myfunc

>>> new = newfunc(100) # new - это функция

>>> new(200)

Функция может и не заканчиваться инструкцией return, при этом функция вернет значениеNone:

>>> def func():

>>> print(func())

Аргументы функции

Функция может принимать произвольное количество аргументов или не принимать их вовсе. Также распространены функции с произвольным числом аргументов, функции с позиционными и именованными аргументами, обязательными и необязательными.

>>> def func(a, b, c=2): # c - необязательный аргумент

Return a + b + c

>>> func(1, 2) # a = 1, b = 2, c = 2 (по умолчанию)

>>> func(1, 2, 3) # a = 1, b = 2, c = 3

>>> func(a=1, b=3) # a = 1, b = 3, c = 2

>>> func(a=3, c=6) # a = 3, c = 6, b не определен

Traceback (most recent call last):

File "", line 1, in

TypeError: func() takes at least 2 arguments (2 given)

Функция также может принимать переменное количество позиционных аргументов, тогда перед именем ставится *:

>>> def func(*args):

>>> func(1, 2, 3, "abc")

(1, 2, 3, "abc")

>>> func(1)

Как видно из примера, args - это кортежиз всех переданных аргументов функции, и с переменной можно работать также, как и с кортежем.

Функция может принимать и произвольное число именованных аргументов, тогда перед именем ставится **:

>>> def func(**kwargs):

Return kwargs

>>> func(a=1, b=2, c=3)

{"a": 1, "c": 3, "b": 2}

>>> func(a="python")

В переменной kwargs у нас хранится словарь, с которым мы, опять-таки, можем делать все, что нам заблагорассудится.

Анонимные функции, инструкция lambda

Анонимные функции могут содержать лишь одно выражение, но и выполняются они быстрее. Анонимные функции создаются с помощью инструкции lambda. Кроме этого, их не обязательно присваивать переменной, как делали мы инструкцией def func():

>>> func = lambda x, y: x + y

>>> func(1, 2)

>>> func("a", "b")

>>> (lambda x, y: x + y)(1, 2)

>>> (lambda x, y: x + y)("a", "b")

lambda функции, в отличие от обычной, не требуется инструкция return, а в остальном, ведет себя точно так же:

>>> func = lambda *args: args

>>> func(1, 2, 3, 4)

19. Понятие рекурсии, реализация в языке Python

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

Проще сказать нельзя. Про рекурсии есть известная поговорка:

Чтобы понять рекурсию, нужно сперва понять рекурсию

Итак, питон позволяет работать с рекурсиями легко и непринужденно. Самый первый пример рекурсии, с которой сталкиваются большинство программистов - это нахождение факториала. Код может быть таким:

def factorial(n):

if n <= 1: return 1

else: return n * factorial(n - 1)

Как видно, мы записали инструкцию if else слегка необычным для питона способом, но это позволяется в данном случаее, ввиду того, что читабельность здесь не ухудшается, но не следует злоупотреблять таким стилем. И вообще, PEP8всех рассудит. :)

Теперь проясним несколько важных особенностей, о которых всегда нужно помнить при работе с рекурсиями.

    Существует ограничение на глубину рекурсии. По умолчанию оно равно 1000.

    Для того, чтобы изменить это ограничение нужно вызвать функцию sys.setrecursionlimit(), а для просмотра текущего лимита sys.getrecursionlimit().

    Не смотря на это - существует ограничение размером стека, который устанавливается операционной системой.

    Рекурсия в Python не может использоваться в функциях-генераторах и сопрограммах. Однако, можно это поведение исправить, но лучше не стоит.

    И последнее - применение декораторов к рекурсивным функциям может приводить к неожиданным результатам, поэтому будьте очень осторожны декорируя рекурсивные функции.

Также, всегда следует определять точки выхода из рекурсивных функций. Это как с циклами - бесконечный цикл может здорово «просадить» вашу операционную систему. И наконец, где лучше применять рекурсию, а где лучше воздержаться и обойтись, например циклами. Конечно, здесь многое зависит от задачи, но всегда следует помнить, что рекурсия в разы медленнее цикла. Так уж устроен питон, что вызов функции дорого вам обходится:) Вообще, в циклах не стоит вызывать функции, а уж рекурсивные функции и подавно.

Рекурсия хорошо подходит там, где производительность не слишком важна, а важнее читабельность и поддержка кода. К примеру, напишите две функции для обхода дерева каталогов, одну рекурсивную, другую с циклами.

Быстрая навигация:
1.31 Списки - массивы. Первое знакомство. 1.30 Функции которые возвращают результат - return 1.29 Подпрограммы: функции и процедуры в Питоне 1.28 Преобразование типов данных - int() 1.27 Ввод данных с клавиатуры - input() 1.26 Типы и размеры данных 1.25 Цикл с предусловием - while. Числа Фибоначчи 1.24 Измерение длины строки, списки 1.23 Срезы строк - вывод определенного количества символов из имеющегося текста 1.22 Строки и управляющие символы 1.21 Системные ошибки в процессе отладки программы 1.20 Оператор ветвления - if, комментарии 1.19 Вывод на печать - print(), быстрый ввод данных, округление, комментарии 1.18 Типы программирования. Часть 2. Объектно-ориентированное программирование 1.17 Типы программирования. Часть 1. Структурное программирование. Циклы 1.16 Представление символьной информации - ASCII 1.15 Деление двоичных чисел 1.14 Математические операции с двоичными числами 1.13 Как хранится и записывается информация. Биты и байты 1.12 Перевод целых чисел десятичной системы счисления в другую систему 1.11 Перевод целых чисел из шестнадцатеричной системы счисления в десятичную 1.10 Перевод целого двоичного числа в шестнадцатеричное 1.9 Перевод целого двоичного числа в другую систему счисления 1.8 Системы счисления 1.7 Булевая алгебра. Логические выражения 1.6 Базовые понятия. Часть 3 - Числа, выражения, операнды, знаки операций 1.5 Базовые понятия. Часть 2 - Программа, данные 1.4 Базовые понятия. Часть 1 - Задача и алгоритм 1.3 Среда разработки СИ 1.2 История языков программирования 1.1 Введение

При написании программ в любом языке программирования необходимо стремиться к написанию компактных кодов, чтобы можно было легко ориентироваться в самом коде.
Бывает что реализовать таким образом свой код не представляется возможным и, зачастую, программный код выглядит как нескончаемой длинны свиток древнего документа, который занимает 10 - 15 экранов монитора по вертикали...
Конечно же разобраться в такой программе бывает крайне сложно самому автору такого творения.

В этом случае на помощь программисту приходит возможность разбиения кода программы на подпрограммы .

Подпрограмма - это некая законченная программа, но не самостоятельная.
Она вызывается из какой то программы более высокого уровня только для выполнения того или иного действия.

Как это выглядит на практике?

К примеру в какой то очень большой программе вам необходимо произвести (мы с вами уже рассматривали алгоритм его работы).
И вместо того, чтобы в этом большом программном коде каждый раз писать еще и код для расчета чисел Фибоначчи, мы просто выносим его в отдельный файл. Это и будет подпрограмма.
Тогда в том месте где должен производиться необходимый расчет этих чисел мы вставляем лишь некое указание на то, чтобы в этом месте была вызвана наша подпрограмма.

В этом случае программный код значительно уменьшается в объеме и разобраться в работе программы будет намного легче.

В разных языках программирования такие подпрограммы называются:

Процедурами или
- функциями

В языке СИ такие подпрограммы называются функциями.

Кстати мы с вами уже применяли функции на практике!
Например мы с вами использовали ВСТРОЕННЫЕ в интерпретатор функции:

Print() - для вывода данных на печать неких параметров, которые были заключены в круглые скобки
- str() - для преобразования данных к строковому типу. Именно ее предварительно запускает функция print()
- int() - для преобразования данных к целому числу
- float() - для преобразования целых чисел в дробный тип
- round() - для округления некоего значения
и т.п.


Итак.
Для вызова функции достаточно набрать ее имя и в скобках перечислить требуемые параметры (аргументы) которые мы хотим передать в данную функцию.

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

def ИМЯ_ФУНКЦИИ(СПИСОК_ПАРАМЕТРОВ):
ПОСЛЕДОВАТЕЛЬНОСТЬ_ВЫРАЖЕНИЙ

Имена функций следует подбирать также, как и имена переменных - по тем же правилам: имя должно начинаться с латинской буквы.
- В списке параметров находятся некие значения, которые передаются в функцию. Эти параметры перечисляются через запятую.

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

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

Def fib(n): a, b = 0, 1 while a < n: print(a, end = " ") a, b = b, a + b print()

Если вкратце, то строка:
a, b = 0, 1
означает запись (но не полностью эквивалентна ей):
a = 0 b = 1

А строка
a, b = b, a + b
означает запись:
a = b b = a + b

Рассмотрим код по строкам:

1
def fib(n):
- определить (def ) функцию по имени fib с параметрами (аргументами) указанными в круглых скобках которые мы хотим передать в эту самую функцию по имени fib .
Т.е. в качестве параметра n мы будем передавать значение для которого будет производиться расчет. Это число будет передаваться в нашу функцию в качестве аргумента.

После двоеточия вводимые данные в интерпретаторе Python печатаются с отступом. Это говорит о том, что эти данные имеют непосредственное отношение к данной функции.

2
a, b = 0, 1
Инициализируем переменные соответствующими значениями:
a = 0 b = 1

3
while a < n:
Оператор цикла while - будет выполняться до тех пор, пока будет выполнено условие цикла a
Здесь также после двоеточия открывается новый блок имеющий НЕПОСРЕДСТВЕННОЕ отношение только к циклу.
Этот блок будет печататься после перевода строки с дополнительным отступом.

4
print(a, end = " ")
Выводим на печать данные переменной а и пробел после каждого витка цикла

5
a, b = b, a + b
Присваиваем переменным соответствующие значения:
a = b b = a + b
Для изменения исходных данных и продолжения работы расчета чисел Фибоначчи

6
print()

Обратите внимание на то, что данный print() нужно печатать ПОД while ... т.е. он уже относится не к телу цикла while , а к телу функции fib
Однако для чего нам нужен второй print() да еще и с пустыми скобками?

В данном случае это вывод пустой строки - сделать "отбивку" - перенос строки. А еще вернее, данная функция выводит на печать символ перевода строки.
В нашем случае можно и не использовать.

Итак мы определили функцию fib для расчета чисел Фибоначчи и она, как вы заметили - не работает.

Для того, чтобы она заработала необходимо ее ВЫЗВАТЬ и передать ей некий параметр для расчетов.
Вызываем нашу функцию и передаем в качестве аргумента значение 40 .
В результате мы должны получить расчет чисел Фибоначчи для всех чисел до 40 :

Печатаем в интерпретаторе Python:
fib(40)
Получаем:

0 1 1 2 3 5 8 13 21 34

Вы можете еще раз вызвать функцию fib() с другим параметром и точно также получите вывод необходимых данных.
Например введем
fib(400)
И получим:

0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

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

Во многих языках программирования процедура и функция не синонимы и имеют отличия друг от друга.
Чем же они отличаются друг от друга в таких языках программирования?

Функция - возвращает значение
- Процедура - не возвращает значение

Поясним на примере:


Если мы можем использовать такую запись (только в качестве примера):
x = fib(n) - то это функция, она присваивает полученное значение переменной x (в данном случае переменной x ничего записано не будет)

Если же возможна только запись fib(n) - то это процедура.

Таким образом мы можем сказать, что наш пример является ПРОЦЕДУРОЙ.

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



Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: