Python. Область видимости, замыкание и чистые функции

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

Области видимости

Глобальная

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

Локальные

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

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

Нелокальные

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

Интерпретатор пайтона работает по лексической области видимости — он ищет переменную в текущей области видимости. Если её нет, то поднимается на область выше и выше, пока не найдёт переменную или поймет, что её нет. Если её не существует во всей программе, то пайтон выкинет исключение NameError.

Замыкание

Функции в пайтоне можно передавать в другие функции как аргумент и возвращать их. Такое поведение возможно у объектов «первого класса».
Это удобно для построения абстракций — получения результата, без понимания внутреннего механизма.

Абстракции помогают проектировать тяжёлые системы, не теряя время на изучение как это работает.
Без них не было бы ОС, браузеров, ютуба, твича и в принципе всего, что сегодня есть на компьютерах.
Подробнее про абстракции будет, когда мы будем проходить SICP.

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

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

Чистые и мутирующие функции

Функции делятся на два типа: те которые что-то меняют в программе и те которые не меняют.

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

def calc_diff(a, b):
    return a - b


print(calc_diff(5, 3))  # Выведется 2

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

В таком варианте функция calc_diff мутирует переменную result.

def calc_diff(a, b):
    global result
    result = a - b


result = 0
print(result) # Выведется 0

calc_diff(5, 3)
print(result)  # Выведется 2

calc_diff(7, 3)
print(result)   # Выведется 4

# Каждый вызов calc_diff() мутирует result

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

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



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

Поделиться
Отправить
Запинить
Популярное