[Перевод] Что можно рассказать о функциях Python на примере кофемашины?

Поделюсь с вами одной из моих любимых аналогий.

Я раньше сам молол себе кофе. Купил такую старомодную ручную кофемолку с металлической воронкой, крутильной рукояткой и маленьким деревянным подносом, на который ссыпается смолотый кофе.

Может быть, где-то у меня она ещё валяется.

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

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

Но ещё эта статья рассказывает о функциях Python. Она в основном о функциях Python.

Так что можете налить себе чашечку кофе — а, кажется, я обещал обойтись без глупых шуток? Извините! — и присаживайтесь поудобнее, слушайте. Возможно, в итоге у вас в голове сварится парочка свежих озарений о том, что можно сделать с функциями на Python — по капельке, по глоточку. [Стивен, стоп!]

Кофемашина. Функция


У кофемашины есть назначение — или, если хотите, функция. Здесь я буду использовать слово «функция» именно в таком общеупотребительном значении.

Причём, у кофемашины есть ровно одна функция — варить кофе.

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

  • Воду
  • Электричество
  • Кофе (допустим, в таблетках, именно такая у меня машина)


Добавляете три этих ингредиента и нажимаете ON. Только не забудьте поставить под носик чашку или кружку.

В машине что-то происходит. Вас не особенно интересует, что именно. Вам нужно только чёрное золото, льющееся вам в чашку. Мммм вкусно.

Вы только что вызвали функцию. Кофемашина — это функция. Сейчас я употребил слово «функция» именно в том значении, которое знакомо программистам.

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

Но давайте разовьём эту аналогию. Здесь ещё много что можно исследовать.

Вы сами собрали себе кофемашину?


Вы купили кофемашину, распаковали её, но начинается её существование не с этого.

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

image


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

image


Она по-прежнему представляет кофемашину. Но теперь мы чётко артикулируем, что нас интересует акт приготовления кофе, а не сама машина — так и должно быть!

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

Одно дело — определять функцию, а другое — вызывать её.

Именно здесь вам и пригодится инструкция к кофемашине. В случае с функцией такую роль может играть строка docstring или страница с документацией. Здесь аналогия тоже удачная. Многие пользователи не читают инструкций — и документацию к коду обычно тоже никто не читает!

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

image


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

Итак:

  • Если вы мастер по кофемашинам, то должны знать, что записать в определение функции. Это текст def make_coffee():
  • Если вы просто хотите чашку кофе, то вам достаточно знать, как обращаться с кофемашиной. Вы должны вызвать make_coffee().


Когда пишешь код, вызывать функции приходится чаще, чем определять. А если вы как я, то не представляете, что находится внутри большинства из тех функций, что вы вызываете. Знаете, как выглядит код, заключённый в def print():? Я тоже не знаю…

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

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

Как сделать чашку кофе


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

У нас в определении функции три параметра: water, electricity и coffee. Эти параметры стоят на месте тех составляющих, которые понадобятся вам для работы.

Параметр water обозначает встроенную в кофемашину ёмкость с водой. Туда наливают воду.
Шнур с вилкой, выходящий из задней стенки машины, называется electricity. Как вы уже догадались, та ячейка, в которую закладывается кофейная таблетка, называется coffee.

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

Давайте вызовем функцию make_coffee():

image


Тогда как имена параметров water, electricity и coffee — это просто метки, используемые при определении функции, аргументы tap_water, electricity_from_wall_socket и blue_espresso_intenso_pod — это конкретные сущности, которые вы применяете при вызове функции, то есть, когда включаете кофемашину.

Можно передавать функции и другие вещи. Например, вы можете обзавестись фильтрами для воды, в таком случае передаёте filtered_water в качестве первого аргумента. Может быть, у вас сейчас проблемы с водопроводом — в таком случае, можно передать bottled_water (бутилированную воду). А вот проточной водой sparkling_water лучше не пользоваться!

А что, если у вас есть электровелосипед, который в стационарном виде может работать в качестве генератора электричества? В таком случае можно передать вторым аргументом electricity_from_stationary_bike, поэтому за каждой варкой кофе вы заодно успеете неплохо размяться.

Не любите эспрессо? Тогда попробуйте caramel_pumpkin_spice_vanilla_latte_pod(кстати, кто-нибудь пил такое?)

Можно передать любой аргумент, если это аргумент подходящего типа. В предыдущем предложении слово «тип» — это не термин. В языке Python применяется утиная типизация, поэтому в данном случае важен не сам тип, а его релевантные характеристики.

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

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

Включаем машину


На кофемашине есть кнопка ON. Чтобы машина заработала, её нужно нажать. Думаю, это понятно и без инструкции по применению.

Что служит кнопкой ON в функции Python? Это скобки, которые вы добавляете вслед за именем функции, выполняющей эту задачу.

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

В коде Python есть существенная разница между make_coffee и make_coffee(). Первый вариант, make_coffee — это имя функции. Оно относится к кофемашине как таковой. Рассмотрим следующую строку на Python:

image


Приведу ещё одну аналогию, которой часто пользуюсь. Оператор присваивания описывает, как вы присваиваете объект переменной с некоторым именем, ставя между ними знак равенства. В таком случае вы как будто кладёте объект Python в коробку. В данном случае коробка называется output. Что же попадает в эту коробку?

Вся кофемашина!


Поскольку make_coffee обозначает кофемашину, вы храните всю кофемашину в коробке output. Функция в Python является объектом. Следовательно, функция хранится в переменной output.

Теперь рассмотрим следующую строку:

image


Да, вы правы! Это не сработает. Но наберитесь терпения и дочитайте абзац. Скобки в данной функции работают как кнопка ON. Вы включили кофемашину, но забыли о трёх важных вещах. Во-первых, в ёмкости нет воды. Из-за этого можно было бы повредить машину, но, вдобавок, вы и не включили её в розетку, поэтому совсем ничего не произойдёт.

Читаете инструкцию. Выясняете, что необходимо передать три аргумента. Что ж, попробуем ещё раз:

image


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

Машина начинает тарахтеть и урчать, после чего возвращает горячий жидкий кофе, который…

…хранится в чашке под названием output. То есть, возвращаемое значение сохраняется в переменной output.

Не забудьте о чашке


Если хотите сохранить возвращаемое значение — не забудьте присвоить его переменной. Рассмотрим следующий код:

image


Вы вызываете функцию. Скобки на месте. Все три аргумента правильные.

Кофемашина начинает ворчать. Уже через полсекунды чувствуется аромат кофе. Буквально. Кофе течёт…

…прямо в сток в нижней панели машины. Вы забыли подставить чашку под носик. Кстати, и я на этой неделе тоже так прокололся — совершенно очевидно, потому что мне требуется чашечка кофе!

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

Вот почему необходимо присваивать возвращаемое значение переменной. На этот раз давайте назовём переменную cup:

image


Может быть, у вас есть и другая функция, drink_beverage(). Логично предположить, что и этой функции требуется аргумент — безалкогольный напиток. Поэтому вы могли бы вызвать drink_beverage(cup).

Но можно вызвать функцию и вот так:

image


Вы вызываете make_coffee() прямо внутри скобок функции drink_beverage(). Когда make_coffee() возвращает значение, оно поступает прямо в drink_beverage() в качестве её аргумента.
Да, это как раз тот сценарий, когда вы подсовываете рот прямо под носик кофемашины.

Внимание: так вы определённо ошпарите себе рот!

Допиваем


Мне нравится аналогия с кофемашиной. Она идеально соответствует законам аналогий от Стивена. Вот эти законы:

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


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

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

image

© Habrahabr.ru