Готовый перевод How to Think Like a Computer Scientist: Learning with Python 2nd Edition. / Как стать программистом: учимся вместе с Python. Второе издание.: Chapter 3 Functions

Внимание! Этот перевод, возможно, ещё не готов, так как модераторы установили для него статус «идёт перевод»

3 Функции

3.1 Определение и использование

В контексте программирования, функции - это именованный кусок кода, выполняющий определенную операцию. Специфика операции обычно определяется именем функции. В python функция определяется следующим образом:

def ИМЯ( список параметров ): операции

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

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

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

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

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

def new_line():
    print # операция print выводит пустую строку

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

Объявление функции не запускает ее. Для запуска функцию необходимо вызвать. Вызов функции содержит ее имя с перечислением передаваемых значений, называемых аргументами, которые заключаются в скобки после имени. Наши первые примеры не содержат никаких параметров, так что функции не передаются никакие аргументы. Отметьте, однако, что наличие круглых скобок в вызове функции обязательно.

print "First Line."
new_line()
print "Second Line."

На выходе программы получим следующее:

First line.

Second line

Пустая строка между двумя надписями - это результат вызова функции new_line(). А что, если нам нужно больше пустых строк между надписями? Мы можем вызвать функцию несколько раз:

print "First Line."
new_line()
new_line()
new_line()
print "Second Line."

Или мы можем написать новую функцию three_lines, которая будет вставлять три пустых строки:

def three_lines():
    new_line()
    new_line()
    new_line()

print "First Line."
three_lines()
print "Second Line."

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

Обратите внимание на пару моментов в этой программе:

Вы можете запускать функцию несколько раз. На самом деле, функции для этого и нужны. Вы можете вызывать одну функцию из тела другой функции; так в функции three_lines происходит вызов new_line.

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

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

Объединим вместе фрагменты кода из предыдущих примеров в скрипт с именем tryme1.py:

def new_line(): print

def three_lines():
    new_line()
    new_line()
    new_line()

print "First Line."
three_lines()
print "Second Line."

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

Как вы могли заметить, создать функцию нужно до ее вызова. Другими словами, объявление функции должно стоять до ее вызова.

3.2 Поток вычислений

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

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

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

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

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

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

И какая мораль у этой запутанной истории? Когда вы читаете программу, не читайте её сверху вниз - следите за потоком вычислений.

3.3 Параметры, аргументы, операция import

Большинсво функций требуются аргументы, значения, которые контролируют выполнение функции. Например, если вам нужно найти абсолютное значение числа, вы можете указать, что это за число. В python есть встроенная функция для вычисления аабсолютного значения:

>>> abs(5)
5
>>> abs(-5)
5

В этом примере, аргументами для функции abs были 5 и -5.

Некоторые функции принимают более одного аргумента. Например, встроенная функция pow принимает два аргумента: основание и степень. Внутри функции значения, переданные функции, становятся переменными, называемыми параметрами.

>>> pow(2, 3)
8
>>> pow(7, 4)
2401

Другая встроенная функция, которая принимает более одного аргумента, это max.

>>> max(7, 11)
11
>>> max(4, 1, 17, 2, 12)
17
>>> max(3 * 11, 5**3, 512 - 9, 1024**0)
503

Функции max может быть передано любое количество аргументов, разделенных запятыми; функция возвращает максимальный из них. Аргументы могут быть простыми значениями или выражениями. В предыдущем примере, результат был - 503, больший из списка 33, 125 и 1.

Приведем пример пользовательской функции, которой передается параметр:

def print_twice(param):
    print param, param

Эта функция принимает один аргумент и передает ее параметру с названием param. Значение параметра (на данный момент мы понятия не имеем, что это за значение) выводится на экран дважды. Имя param мы выбрали исходя из того, что это параметр, но главное, для своих функций выбирайте имена параметров, характеризующих их назначение в функции.

Оболочка python предоставляет нам удобный способ проверки работоспособности наших функций. Мы можем воспользоваться операцией import для вызова наших из скрипта, в котором онаи были объявлены. Чтобы посмотреть, как это работает, представим, что у нас есть функция print_twice, объявленная в скрипте chap03.py. Теперь мы можем импортировать ее в нашу оболочку:

>>> from chap03 import *
>>> print_twice('Spam')
Spam Spam
>>> print_twice(5)
5 5
>>> print_twice(3.14159)
3.14159 3.14159

Во время вызова функции, значение аргумента связывается с соответствующим параметром, определенным в функции во время ее объявления. В итоге, параметр param становится равным 'Spam', если вызывается функция print_twice('Spam'), param = 5 в print_twice(5), и param = 3.14159 в print_twice(3.14159).

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

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

>>> print_twice('Spam' * 4)
SpamSpamSpamSpam SpamSpamSpamSpam

'Spam'*4 сначала преобразуется в 'SpamSpamSpamSpam', а затем передается в качестве аргумента функции print_twice.

3.4 Композиция

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

>>> print_twice(abs(-7))
7 7
>>> print_twice(max(3, 1, abs(-11), 7))
11 11

В первом примере, abs(-7) дает значение 7, которое передается аргументом в print_twice. Во втором примере у нас двухуровневая композиция, сначала abs(-11) дает 11, потом max(3, 1, 11, 7) дает 11, и, наконец, print_twice(11) выводит 11 дважды.

Ещё мы можем использовать переменные в качестве аргументов.

>>> sval = 'Eric, the half a bee.'
>>> print_twice(sval)
Eric, the half a bee. Eric, the half a bee.

Вот здесь произошло нечто важное. Мы передали имя переменной в качестве аргумента (sval), не изменяя при этом имя переменной (param). Опять таки, во время вызова функции принимается, что param = sval. Не важно какое имя носит передаваемая в качестве аргумента переменная, внутри функции, она будет носить имя param.

3.5 Локальные переменные и параметры

Когда вы создаете локальную переменную внутри функции, она существует только в теле функции, этой переменной нет за ее пределами. Например:

def cat_twice(part1, part2):
    cat = part1 + part2
    print_twice(cat)

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

>>> chant1 = "Pie Jesu domine, "
>>> chant2 = "Dona eis requiem."
>>> cat_twice(chant1, chant2)
Pie Jesu domine, Dona eis requiem. Pie Jesu domine, Dona eis requiem.

Когда cat_twice завершится, переменная cat уничтожается. Если мы попробуем напечатать её, то получим сообщение об ошибке:

>>> print cat
NameError: имя 'cat' не определено

Параметры так же локальны. Например, за пределами функции print_twice, нет такой переменной как param. Если вы попробуете воспользоваться ею, python вам обязательно пожалуется.

3.6 Диаграмма стеков

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

Каждая функция представляется определенной областью, фреймом. Фрейм - это прямоугольник с именем функции снаружи и параметрами и переменными внутри.

Порядок расположения фреймов в диаграмме стеков показывает движение потока вычислений. Функция print_twice была вызвана функцией cat_twice, которая, в свою очередь, была вызвана функцией __main__, которая является специальной функцией верхнего времени. Когда вы создаете переменную вне всяких функций, она лежит внутри функции __main__.

Каждый параметр относится к определенному значению, которое передает аргумент. Так, part1 имеет тоже значение, что и chant1, а part2 - то же, что и chant2, и param - то же, что и cat.

Если во время вызова функции произошла ошибка, python пишет имя функции, и имя вызывающей функции, и имя функции, вызывающей предыдущую, и так до самого верха, до главной функции.

Чтобы увидеть, как это работает, создадим скрипт tryme2.py:

def print_twice(param):
    print param, param
    print cat

def cat_twice(part1, part2):
    cat = part1 + part2
    print_twice(cat)

hant1 = "Pie Jesu domine, "
chant2 = "Dona eis requim."
cat_twice(chant1, chant2)

Мы добавили операцию вывода на экран значения переменной cat в функции print_twice, но эта переменная не определена. Запуск этой переменной вернет следующую ошибку:

Обратная трассировка (полный путь):
Файл "tryme2.py", строка 11, в <module> cat_twice(chant1, chant2)
Файл "tryme2.py", строка 7, в cat_twice print_twice(cat)
Файл "tryme2.py", строка 3, в print_twice print cat
NameError: глобальное имя 'cat' не определено

Этот список функций называется обратной трассировкой. Она показывает, в каком именно файле, какой функции и какой строке возникла ошибка. Так же она покажет строку кода, в которой возникла ошибка.

Обратите внимание на сходство обратной трассировки и диаграммой стеков. Это не совпадение. На самом деле, другое название обратной трассировки - это стековая трассировка.

3.7 Словарь

Аргумент - значение, передаваемое функции во время ее вызова. Это значение присваивается параметру функции.
Тело - Вторая часть составного выражения. Тело содержит перечень инструкций, написанных с одинаковым отступом относительно заголовка. Стандартный шаг отступа в python - четыре пробела.

Составное выражение - выражение, состоящее из двух частей:

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

Синтаксис составного выражения выглядит следующим образом:

Ключевое слово имя:
    операция
    операция

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

import - операция добавление функций и переменных, объявленных в скриптах python для использования в окружении других скриптов или оболочке. Например, напишем следующий скрипт (tryme.py):

def print_thrice(thing):
    print thing, thing, thing

n = 42
s = "And now for something completely different..."

Теперь запустим оболочку python в том же каталоге, в котором находится наш скрипт:

$ ls
tryme.py
$ python
>>>

В скрипте tryme.py определено три имени: print_thrice, n, и s. Если мы попробуем получить доступ к любому из них без операции import, получим ошибку:

>>> n
Traceback (most recent call last): File "<stdin>", line 1, in <module>
NameError: name 'n' is not defined
>>> print_thrice("ouch!")
Traceback (most recent call last): File "<stdin>", line 1, in <module>
NameError: name 'print_thrice' is not defined

Если мы импортируем все из скрипта tryme.py, то сможем использовать любое объявленное в нем имя:

>>> from tryme import *
>>> n
42
>>> s
'And now for something completely different...'
>>> print_thrice("Yipee!")
Yipee! Yipee! Yipee!
>>>

В выражении import не нужно писать расширение .py в имени скрипта.

Локальная переменная - переменная, определенная внутри функции.
Параметр - имя, используемое внутри функции для ссылки на переменную, переданную аргументом.
Обратная трассировка - список вызванных функций, который выводится при возникновении ошибки выполнения. Обратная трассировка похожа на стековую трассировку, которая представляет из себя список функций в порядке их выполнения.

3.8 Упражнения

С помощью текстового редактора создайте скрипт, назвав его tryme3.py. Напишите функцию nine_lines для вывода на экран девяти пустых строк. Далее напишите функцию clear_screen для вывода на экран двадцати пяти пустых строк. В последней строке программы должен стоять вызов функции clear_screen.

Переместите последнюю строку в tryme3.py на самый верх так, чтобы функция clear_screen вызывалась раньше, чем объявлялась. Запустите программу и посмотрите, какую ошибку вы получите. Вы можете сформировать правило по поводу объявления и вызова функций, в котором указывается порядох их написания в тексте программы?

Вернитесь к рабочей версии программы tryme3.py. Поместите объявление функции new_line после объявления функции three_lines. Посмотрите, что получится при запуске программы. Теперь переместите объявление функции new_line до вызова функции three_lines(). Объясните, как правило расположения объявления и вызова функций работает в этом примере.

Заполните тело объявления функции cat_n_times так, чтобы строка s выводилась n раз.

def cat_n_times(s, n):
    <поместите сюда свой код>

Сохраните эту функцию в скрипте import_test.py. Теперь в оболочке unix проверте, что находитесь в том же каталоге, что и файл скрипта (команда ls). Запустите оболочку python и выполните следующее:

>>> from import_test import *
>>> cat_n_times('Spam', 7)
SpamSpamSpamSpamSpamSpamSpam

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

Внимание! Этот перевод, возможно, ещё не готов.
Его статус: идёт перевод

Переведено на Нотабеноиде
http://notabenoid.org/book/9398/29010

Переводчики: czech

Настройки

Готово:

100.00% КП = 1.0