Функции ======= Функции -- это многократно используемые фрагменты программы. Они позволяют дать имя определённому блоку команд с тем, чтобы впоследствии запускать этот блок по указанному имени в любом месте программы и сколь угодно много раз. Это называется *вызовом* функции. Мы уже использовали много встроенных функций, как то ``len`` и ``range``. Функция -- это, пожалуй, *наиболее* важный строительный блок любой нетривиальной программы (на любом языке программирования), поэтому в этой главе мы рассмотрим различные аспекты функций. Функции определяются при помощи зарезервированного слова ``def``. После этого слова указывается *имя* функции, за которым следует пара скобок, в которых можно указать имена некоторых переменных, и заключительное двоеточие в конце строки. Далее следует блок команд, составляющих функцию. На примере можно видеть, что на самом деле это очень просто: **Пример:** (сохраните как ``function1.py``) .. sourcecode:: python def sayHello(): print('Привет, Мир!') # блок, принадлежащий функции # Конец функции sayHello() # вызов функции sayHello() # ещё один вызов функции **Вывод:** :: $ python function1.py Привет, Мир! Привет, Мир! **Как это работает:** Мы определили функцию с именем ``sayHello``, используя описанный выше синтаксис. Эта функция не принимает параметров, поэтому в скобках не объявлены какие-либо переменные. Параметры функции -- это некие входные данные, которые мы можем передать функции, чтобы получить соответствующий им результат. Обратите внимание, что мы можем вызывать одну и ту же функцию много раз, а значит нет необходимости писать один и тот же код снова и снова. Параметры функций ----------------- Функции могут принимать параметры, т.е. некоторые значения, передаваемые функции для того, чтобы она что-либо *сделала* с ними. Эти параметры похожи на переменные, за исключением того, что значение этих переменных указывается при вызове функции, и во время работы функции им уже присвоены их значения. Параметры указываются в скобках при объявлении функции и разделяются запятыми. Аналогично мы передаём значения, когда вызываем функцию. Обратите внимание на терминологию: имена, указанные в объявлении функции, называются *параметрами*, тогда как значения, которые вы передаёте в функцию при её вызове, -- *аргументами*. **Пример:** (сохраните как ``func_param.py``) .. sourcecode:: python def printMax(a, b): if a > b: print(a, 'максимально') elif a == b: print(a, 'равно', b) else: print(b, 'максимально') printMax(3, 4) # прямая передача значений x = 5 y = 7 printMax(x, y) # передача переменных в качестве аргументов **Вывод:** :: $ python func_param.py 4 максимально 7 максимально **Как это работает:** Здесь мы определили функцию с именем ``printMax``, которая использует два параметра с именами ``a`` и ``b``. Мы находим наибольшее число с применением простого оператора ``if..else`` и выводим это число. При первом вызове функции ``printMax`` мы напрямую передаём числа в качестве аргументов. Во втором случае мы вызываем функцию с переменными в качестве аргументов. ``printMax(x, y)`` назначает значение аргумента ``x`` параметру ``a``, а значение аргумента ``y`` -- параметру ``b``. В обоих случаях функция ``printMax`` работает одинаково. Локальные переменные -------------------- При объявлении переменных внутри определения функции, они никоим образом не связаны с другими переменными с таким же именем за пределами функции -- т.е. имена переменных являются *локальными* в функции. Это называется *областью видимости* переменной. Область видимости всех переменных ограничена блоком, в котором они объявлены, начиная с точки объявления имени. **Пример:** (сохраните как ``func_local.py``) .. sourcecode:: python x = 50 def func(x): print('x равен', x) x = 2 print('Замена локального x на', x) func(x) print('x по-прежнему', x) **Вывод:** :: $ python func_local.py x равен 50 Замена локального x на 2 x по-прежнему 50 **Как это работает:** При первом выводе *значения*, присвоенного имени ``x``, в первой строке функции Python использует значение параметра, объявленного в основном блоке, выше определения функции. Далее мы назначаем ``x`` значение ``2``. Имя ``x`` локально для нашей функции. Поэтому когда мы заменяем значение ``x`` в функции, ``x``, объявленный в основном блоке, остаётся незатронутым. Последним вызовом функции ``print`` мы выводим значение ``x``, указанное в основном блоке, подтверждая таким образом, что оно не изменилось при локальном присваивании значения в ранее вызванной функции. Зарезервированное слово "global" -------------------------------- Чтобы присвоить некоторое значение переменной, определённой на высшем уровне программы (т.е. не в какой-либо области видимости, как то функции или классы), необходимо указать Python, что её имя не локально, а *глобально* (*global*). Сделаем это при помощи зарезервированного слова ``global``. Без применения зарезервированного слова ``global`` невозможно присвоить значение переменной, определённой за пределами функции. Можно использовать уже существующие значения переменных, определённых за пределами функции (при условии, что внутри функции не было объявлено переменной с таким же именем). Однако, это не приветствуется, и его следует избегать, поскольку человеку, читающему текст программы, будет непонятно, где находится объявление переменной. Использование зарезервированного слова ``global`` достаточно ясно показывает, что переменная объявлена в самом внешнем блоке. **Пример:** (сохраните как ``func_global.py``) .. sourcecode:: python x = 50 def func(): global x print('x равно', x) x = 2 print('Заменяем глобальное значение x на', x) func() print('Значение x составляет', x) **Вывод:** :: $ python func_global.py x равно 50 Заменяем глобальное значение x на 2 Значение x составляет 2 **Как это работает:** Зарезервированное слово ``global`` используется для того, чтобы объявить, что ``x`` -- это глобальная переменная, а значит, когда мы присваиваем значение имени ``x`` внутри функции, это изменение отразится на значении переменной ``x`` в основном блоке программы. Используя одно зарезервированное слово ``global``, можно объявить сразу несколько переменных: ``global x, y, z``. .. Отсутствует в версии 2.0 Зарезервированное слово "nonlocal" ---------------------------------- Мы увидели, как получать доступ к переменным в локальной и глобальной области видимости. Есть ещё один тип области видимости, называемый "нелокальной" (``nonlocal``) областью видимости, который представляет собой нечто среднее между первыми двумя. Нелокальные области видимости встречаются, когда вы определяете функции внутри функций. Поскольку в Python всё является выполнимым кодом, вы можете определять функции где угодно. **Давайте рассмотрим пример:** .. sourcecode:: python # Filename: func_nonlocal.py def func_outer(): x = 2 print('x равно', x) def func_inner(): nonlocal x x = 5 func_inner() print('Локальное x сменилось на', x) func_outer() **Вывод:** :: $ python func_nonlocal.py x равно 2 Локальное x сменилось на 5 **Как это работает:** Когда мы находимся внутри ``func_inner``, переменная ``x``, определённая в первой строке ``func_outer`` находится ни в локальной области видимости (определение переменной не входит в блок ``func_inner``), ни в глобальной области видимости (она также и не в основном блоке программы). Мы объявляем, что хотим использовать именно эту переменную ``x``, следующим образом: ``nonlocal x``. Попробуйте заменить "``nonlocal x``" на "``global x``", а затем удалить это зарезервированное слово, и пронаблюдайте за разницей между этими двумя случаями. Значения аргументов по умолчанию -------------------------------- Зачастую часть параметров функций могут быть *необязательными*, и для них будут использоваться некоторые заданные значения по умолчанию, если пользователь не укажет собственных. Этого можно достичь с помощью значений аргументов по умолчанию. Их можно указать, добавив к имени параметра в определении функции оператор присваивания (``=``) с последующим значением. Обратите внимание, что значение по умолчанию должно быть константой. Или точнее говоря, оно должно быть неизменным\ [1]_ -- это объясняется подробнее в последующих главах. А пока запомните это. **Пример:** (сохраните как ``func_default.py``) .. sourcecode:: python def say(message, times = 1): print(message * times) say('Привет') say('Мир', 5) **Вывод:** :: $ python func_default.py Привет МирМирМирМирМир **Как это работает:** Функция под именем ``say`` используется для вывода на экран строки указанное число раз. Если мы не указываем значения, по умолчанию строка выводится один раз. Мы достигаем этого указанием значения аргумента по умолчанию, равного ``1`` для параметра ``times``\ [2]_. При первом вызове ``say`` мы указываем только строку, и функция выводит её один раз. При втором вызове ``say`` мы указываем также и аргумент ``5``, обозначая таким образом, что мы хотим *сказать*\ [3]_ фразу 5 раз. .. important:: Значениями по умолчанию могут быть снабжены только параметры, находящиеся в конце списка параметров. Таким образом, в списке параметров функции параметр со значением по умолчанию не может предшествовать параметру без значения по умолчанию. Это связано с тем, что значения присваиваются параметрам в соответствии с их положением. Например, ``def func(a, b=5)`` допустимо, а ``def func(a=5, b)`` -- *не допустимо*. Ключевые аргументы ------------------ Если имеется некоторая функция с большим числом параметров, и при её вызове требуется указать только некоторые из них, значения этих параметров могут задаваться по их имени -- это называется *ключевые параметры*. В этом случае для передачи аргументов функции используется имя (ключ) вместо позиции (как было до сих пор). Есть два *преимущества* такого подхода: во-первых, использование функции становится легче, поскольку нет необходимости отслеживать порядок аргументов; во-вторых, можно задавать значения только некоторым избранным аргументам, при условии, что остальные параметры имеют значения аргумента по умолчанию. **Пример:** (сохраните как ``func_key.py``) .. sourcecode:: python def func(a, b=5, c=10): print('a равно', a, ', b равно', b, ', а c равно', c) func(3, 7) func(25, c=24) func(c=50, a=100) **Вывод:** :: $ python func_key.py a равно 3, b равно 7, а c равно 10 a равно 25, b равно 5, а c равно 24 a равно 100, b равно 5, а c равно 50 **Как это работает:** Функция с именем ``func`` имеет один параметр без значения по умолчанию, за которым следуют два параметра со значениями по умолчанию. При первом вызове, ``func(3, 7)``, параметр ``a`` получает значение ``3``, параметр ``b`` получает значение ``7``, а ``c`` получает своё значение по умолчанию, равное ``10``. При втором вызове ``func(25, c=24)`` переменная ``a`` получает значение 25 в силу позиции аргумента. После этого параметр ``c`` получает значение ``24`` по имени, т.е. как ключевой параметр. Переменная ``b`` получает значение по умолчанию, равное ``5``. При третьем обращении ``func(c=50, a=100)`` мы используем ключевые аргументы для всех указанных значений. Обратите внимание на то, что мы указываем значение для параметра ``c`` перед значением для ``a``, даже несмотря на то, что в определении функции параметр ``a`` указан раньше ``c``. Переменное число параметров [4]_ -------------------------------- .. TODO Может, стоит написать об этом в последующих главах, ведь мы ещё не говорили о списках и словарях? Иногда бывает нужно определить функцию, способную принимать *любое* число параметров. Этого можно достичь при помощи звёздочек (сохраните как ``function_varargs.py``): .. sourcecode:: python def total(a=5, *numbers, **phonebook): print('a', a) #проход по всем элементам кортежа for single_item in numbers: print('single_item', single_item) #проход по всем элементам словаря for first_part, second_part in phonebook.items(): print(first_part,second_part) total(10,1,2,3,Jack=1123,John=2231,Inge=1560) **Вывод:** :: $ python function_varargs.py a 10 single_item 1 single_item 2 single_item 3 Inge 1560 John 2231 Jack 1123 None **Как это работает:** Когда мы объявляем параметр со звёздочкой (например, ``*param``), все позиционные аргументы начиная с этой позиции и до конца будут собраны в кортеж под именем ``param``. Аналогично, когда мы объявляем параметры с двумя звёздочками (``**param``), все ключевые аргументы начиная с этой позиции и до конца будут собраны в словарь под именем ``param``. Мы изучим кортежи и словари в :ref:`одной из последующих глав `. Только ключевые параметры ------------------------- Если некоторые ключевые параметры должны быть доступны только по ключу, а *не* как позиционные аргументы, их можно объявить после параметра со звёздочкой (сохраните как ``keyword_only.py``): .. sourcecode:: python def total(initial=5, *numbers, extra_number): count = initial for number in numbers: count += number count += extra_number print(count) total(10, 1, 2, 3, extra_number=50) total(10, 1, 2, 3) # Вызовет ошибку, поскольку мы не указали значение # аргумента по умолчанию для 'extra_number'. **Вывод:** :: $ python keyword_only.py 66 Traceback (most recent call last): File "keyword_only.py", line 12, in total(10, 1, 2, 3) TypeError: total() needs keyword-only argument extra_number **Как это работает:** Объявление параметров после параметра со звёздочкой даёт только ключевые аргументы. Если для таких аргументов не указано значение по умолчанию, и оно не передано при вызове, обращение к функции вызовет ошибку, в чём мы только что убедились. Обратите внимание на использование ``+=``, который представляет собой сокращённый оператор, позволяющий вместо ``x = x + y`` просто написать ``x += y``. Если вам нужны аргументы, передаваемые только по ключу, но не нужен параметр со звёздочкой, то можно просто указать одну звёздочку без указания имени: ``def total(initial=5, *, extra_number)``. Оператор "return" ----------------- Оператор ``return`` используется для возврата\ [5]_ из функции, т.е. для прекращения её работы и выхода из неё. При этом можно также *вернуть некоторое значение* из функции. **Пример:** (сохраните как ``func_return.py``) .. sourcecode:: python #!/usr/bin/python # Filename: func_return.py def maximum(x, y): if x > y: return x elif x == y: return 'Числа равны.' else: return y print(maximum(2, 3)) **Вывод:** :: $ python func_return.py 3 **Как это работает:** Функция ``maximum`` возвращает максимальный из двух параметров, которые в данном случае передаются ей при вызове. Она использует обычный условный оператор ``if..else`` для определения наибольшего числа, а затем *возвращает* это число. Обратите внимание, что оператор ``return`` без указания возвращаемого значения эквивалентен выражению ``return None``. ``None`` -- это специальный тип данных в Python, обозначающий ничего. К примеру, если значение переменной установлено в ``None``, это означает, что ей не присвоено никакого значения. Каждая функция содержит в неявной форме оператор ``return None`` в конце, если вы не указали своего собственного оператора ``return``. В этом можно убедиться, запустив ``print(someFunction())``, где функция ``someFunction`` -- это какая-нибудь функция, не имеющая оператора ``return`` в явном виде. Например: .. sourcecode:: python def someFunction(): pass Оператор ``pass`` используется в Python для обозначения пустого блока команд. .. note:: Существует встроенная функция ``max``, в которой уже реализован функционал "поиск максимума", так что пользуйтесь этой встроенной функцией, где это возможно. Строки документации [6]_ ------------------------ Python имеет остроумную особенность, называемую *строками документации*, обычно обозначаемую сокращённо *docstrings*. Это очень важный инструмент, которым вы обязательно должны пользоваться, поскольку он помогает лучше документировать программу и облегчает её понимание. Поразительно, но строку документации можно получить, например, из функции, даже во время выполнения программы! **Пример:** (сохраните как ``func_doc.py``) .. sourcecode:: python def printMax(x, y): '''Выводит максимальное из двух чисел. Оба значения должны быть целыми числами.''' x = int(x) # конвертируем в целые, если возможно y = int(y) if x > y: print(x, 'наибольшее') else: print(y, 'наибольшее') printMax(3, 5) print(printMax.__doc__) **Вывод:** :: $ python func_doc.py 5 наибольшее Выводит максимальное из двух чисел. Оба значения должны быть целыми числами. **Как это работает:** Строка в первой логической строке функции является *строкой документации* для этой функции. Обратите внимание на то, что строки документации применимы также к :doc:`модулям ` и :doc:`классам `, о которых мы узнаем в соответствующих главах. Строки документации принято записывать в форме многострочной\ [7]_ строки, где первая строка начинается с заглавной буквы и заканчивается точкой. Вторая строка оставляется пустой, а подробное описание начинается с третьей. Вам *настоятельно рекомендуется* следовать такому формату для всех строк документации всех ваших нетривиальных функций. Доступ к строке документации функции ``printMax`` можно получить с помощью атрибута этой функции (т.е. имени, принадлежащего ей) ``__doc__`` (обратите внимание на *двойное подчёркивание*). Просто помните, что Python представляет *всё* в виде объектов, включая функции. Мы узнаем больше об объектах в главе :doc:`о классах `. Если вы пользовались функцией ``help()`` в Python, значит вы уже видели строки документации. Эта функция просто-напросто считывает атрибут ``__doc__`` соответствующей функции и аккуратно выводит его на экран. Вы можете проверить её на рассмотренной выше функции: просто включите ``help(printMax)`` в текст программы. Не забудьте нажать клавишу ``q`` для выхода из справки (``help``). Точно так же автоматические инструменты могут получать документацию из программы. Именно поэтому я *настоятельно рекомендую* вам использовать строки документации для любой нетривиальной функции, которую вы пишете. Команда ``pydoc``, поставляемая вместе с пакетом Python, работает аналогично функции ``help()``. Аннотации --------- Функции имеют ещё одну дополнительную возможность, называемую аннотациями, которые предоставляют отличный способ сопровождения каждого параметра, равно как и возвращаемого значения дополнительной информацией. Поскольку сам язык Python не интерпретирует эти аннотации каким-либо способом (этот функционал отводится посторонним библиотекам), мы опустим эту возможность из нашего обсуждения. Если вам интересно почитать об аннотациях, просмотрите :pep:`3107`. Резюме ------ Мы рассмотрели достаточно много аспектов функций, но тем не менее, вы должны понимать, что это далеко не все их аспекты. В то же время, мы охватили большинство того, с чем вы будете сталкиваться при повседневном использовании функций в Python. Далее мы увидим, как использовать и создавать модули Python. Примечания ---------- .. [1] "immutable" в терминологии Python (*прим. перев.*) .. [2] times -- *англ.* "раз" (*прим. перев.*) .. [3] say -- *англ.* "сказать" (*прим. перев.*) .. [4] VarArgs -- *от англ.* "**Var**\ iable number of **Arg**\ ument\ **s**" -- "переменное число аргументов" (*прим. перев.*) .. [5] return -- *англ.* "возврат" (*прим. перев.*) .. [6] DocString - *от англ.* "**Doc**\ umentation **String**" -- "строка документации" (*прим. перев.*) .. [7] т.е. строки, содержащей символы перевода строки. (*прим. перев*)