Курс по Python: https://stepik.org/course/100707
Этим занятием мы открываем с вами одну из ключевых тем в программировании – функции.
Что это такое?
Условно, их можно представить как активный объект, который не просто хранит
какие-либо данные, а выполняет заданный фрагмент программы. Ссылка на такой
объект называется именем функции. Например, знакомая нам функция print выполняет вывод
в консоль переданных ей данных. Имя этой функции так и можно воспринимать, как
ссылку на свой объект-функцию. Действительно, если в интерактивном режиме
напечатать имя print, то увидим, что оно ссылается на
встроенную функцию. Чтобы активизировать программу, заложенную в объект-функцию,
нужно поставить круглые скобки после имени функции:
Теперь был
исполнен определенный код и в консоль была выведена пустая строка. Эти круглые
скобки являются оператором вызова функций. То есть, само по себе имя – это
ссылка на функцию, а имя функции с круглыми скобками – это уже вызов функции.
Вот этот момент нужно очень хорошо и четко понимать, чтобы уметь правильно
обращаться с функциями при построении программ.
Итак, раз print – это ссылка на
функцию, то что нам тогда мешает создать еще одну ссылку на этот же
объект-функцию, через оператор присваивания:
И вызвать ее
через второе имя f:
Как видите, все
работает. Теперь функцию print можно вызывать и
через f. А можно ли
тогда исходному имени функции print присвоить другой объект, например,
строку:
print = "это была функция print"
Да, и это нам
никто не мешает делать. Теперь прежнюю функцию можно вызвать только через имя f:
То есть, имя
функции – это просто ссылка на объект-функцию и не более того. Конечно,
заменять стандартные имена функций на другие, без острой необходимости не
стоит. А вначале лучше совсем этого не делать. Именно этого правила и следует
придерживаться.
Хорошо, мы
теперь знаем, как правильно воспринимать функцию в Python. Но зачем они
нужны? Разве нельзя писать программы и без них? Конечно можно. И самые первые
языки программирования их даже не имели. Но писать программы без них, это все
равно, что поехать в другой город на лошади, а не на автомобиле. С функциями
программы становятся более модульными, а процесс программирования значительно
упрощается. Так за счет чего это происходит?
Допустим, мы
пишем программу, в которой постоянно нужно делать отправку электронных писем по
одному и тому же алгоритму. В результате, у нас в программе будут постоянно
появляться одни и те же строчки кода для отправки писем. Такое дублирование
программного кода негативно влияет на надежность программ, возможность их
быстрого редактирования, читабельности и т.п. В программирование это называется
кратко:
DRY –
Don’t Repeat Yourself
Как только, вы
замечаете в программе повторение (дублирование) кода, значит, неверно строите
ее архитектуру и структуру кода следует пересмотреть. Это очень грубая ошибка в
программировании.
Так вот, чтобы
нам устранить дублирование при отправке электронных писем, повторяющийся
фрагмент можно поместить в функцию, а затем, вызывать ее в нужных местах программы.
Это первое, для чего были введены функции в языки программирования – устранять
дублирование кода.
В Python существует
множество стандартных, встроенных функций, но на все случаи жизни их не
придумаешь. Поэтому, программист может сам создавать свои собственные по мере
необходимости. Для этого используется следующий синтаксис:
def <имя функции>([список аргументов]):
оператор 1
оператор 2
…
оператор
N
Здесь имя
функции придумывается программистом подобно именам переменных и, так как
функция – это определенное действие, то ее имя следует выбирать как глагол,
например:
go,
show, get, set и т.п.
Далее, идет
набор операторов, которые образуют тело функции. Именно они начинают
выполнятся при ее вызове.
Давайте в качестве
примера, зададим простую функцию, которая будет имитировать отправку письма:
def send_mail():
text = "Уважаемый, Сергей Балакирев! Я так и не понял, что такое функция. Объясните лучше!"
print(text)
Обратите
внимание, имя функции send_mail – фраза-глагол,
действие. Кроме того, два разных слова send и mail отделены
символом подчеркивания. Я его записал для лучшей читаемости текста программы. И,
глядя на название функции, сразу понятно, что она должна делать. Это
рекомендуемый подход к программированию – называть переменные и функции
понятными именами.
Тело этой
функции состоит из двух команд: переменной text со строкой и
функции print(). Так как вы
дошли до этого урока, то должны хорошо понимать, почему эти две строчки
образуют единый блок операторов тела функции. Да, у них у всех единый отступ от
левого края. Здесь все также, как и в условных операторах или операторах
циклов. Поэтому повторяться не буду.
Итак, мы с вами
определили функцию. Но, если сейчас запустить эту программу, то в консоли
ничего не увидим, то есть, функция не сработала. Все верно, на данном этапе мы
лишь определили, объявили функцию, но еще не вызывали. Как я говорил вначале,
для вызова функции нужно записать ее имя и поставить круглые скобки – оператор
вызова функции:
Теперь, при
запуске программы, мы видим заветное сообщение. Обратите внимание, я записал
вызов функции через две пустые строки после объявления функции. Это оформление
по рекомендации стандарта PEP8. В интегрированной среде PyCharm, чтобы привести
текст программы в соответствие с этим стандартом, достаточно нажать комбинацию
клавиш Alt + Ctrl + L.
Эту же функцию мы
можем вызвать и дважды:
Соответственно,
она сработает два раза подряд. И еще, обратите внимание, мы можем вызывать
функцию только после ее объявления. То есть, сначала сделать ее вызов, а потом
объявить не получится, возникнет ошибка, что имя send_mail не определено.
Нужно сначала объявлять функции и только потом их вызывать.
Вернем два
подряд идущих вызова функции send_mail() и посмотрим в режиме отладки, как
будет выполняться эта программа (показываем). Если нажать F8, то мы сразу
выполним функцию. Чтобы зайти внутрь ее нужно нажать клавишу F7. А в теле
функции уже можно F8. Так будет понятнее, как выполняется эта
программа.
Сейчас у нашей
функции нет никаких параметров. Давайте добавим один с именем отправителя:
def send_mail(from_name):
text = f"""Уважаемый, Сергей Балакирев!
Я так и не понял, что такое функция.
Объясните лучше!
Ваш, навсегда {from_name}!"""
print(text)
Для этого в
круглых скобках записываем параметр с именем from_name (это имя мы
придумываем сами, я решил назвать так) и, затем, в многострочной F-строке мы
добавим это имя в конце сообщения.
Теперь функцию send_mail() следует
вызывать с одним аргументом и по нашей задумке этот аргумент должен быть
строкой, поэтому, запишем вызов, так:
send_mail("Иван Иванович")
а второй вызов
поставим в комментарий. После запуска программы увидим сформированное
сообщение. Здесь важно понять, как все это работает.
Во-первых,
обратите внимание на терминологию. Определение внутри функции называется
параметром, а передаваемое значение при вызове функции – аргументом. В
дальнейшем, я буду пользоваться этими словами именно в этом смысле. Во-вторых,
когда происходит вызов функции, то параметр ссылается на переданный аргумент. В
итоге, в теле функции from_name принимает
значение "Иван Иванович", которое и подставляется в шаблон сообщения.
Давайте
посмотрим, как это происходит в режиме отладки (показываем).
А что будет, если
теперь попытаться вызвать эту же функцию без аргументов, так как мы это делали
вначале? (Убираем комментарий). Здесь уже возникает ошибка, что функций ожидает
один аргумент, а мы ничего не передаем. То же самое будет, если передать больше
аргументов, например, два:
send_mail("Иван Иванович", "Сергей Балакирев")
То есть, функции
нужно передавать ровно столько аргументов, сколько параметров в ней определено.
Давайте пропишем второй параметр – возраст отправителя:
def send_mail(from_name, old):
text = f"""Уважаемый, Сергей Балакирев!
Я так и не понял, что такое функция.
Объясните лучше!
Ваш, навсегда {from_name}! И не судите строго, мне всего {old} лет."""
print(text)
Как видите,
параметры записываются в круглых скобках через запятую и принимают значения
аргументов при вызове функции:
send_mail("Иван Иванович", 7)
send_mail("Иван Иванович", "Сергей Балакирев")
Причем, на
первый аргумент ссылается первый параметр, а на второй – второй. То есть,
порядок здесь имеет значение. Также, смотрите, при втором вызове у нас вместо
числа указана строка. Параметру все равно на какой тип данных ссылаться, так
как в Python используется
динамическая типизация (мы об этом ранее говорили). В итоге, второе сообщение
несколько бессмысленно, но, тем не менее, все сработало без ошибок.
Итак, на этом
первом занятии по функциям, мы с вами узнали, что это такое и зачем они нужны,
как объявляются функции и как они вызываются с разным числом аргументов. Для
закрепления этого материала пройдите практические задания и переходите к
следующему уроку, где мы продолжим изучение этой темы.
Курс по Python: https://stepik.org/course/100707