Как обратиться к переменной из другой функции python
В Python функция фактически представляет отдельный тип. Так мы можем присвоить переменной какую-нибудь функцию и затем, используя переменную, вызывать данную функцию. Например:
В данном случае переменной message присваивается одна из функций. Сначала ей передается функция say_hello() :
После этого переменная message будет указывать на данную функцию, то есть фактически представлять функцию say_hello. А это значит, что мы можем вызывать переменную message как обычную функцию:
Фактически это приведет к выполнению функции say_hello, и на консоль будет выведена строка «Hello». Затем подобным образом мы можем передать переменной message другую функцию и вызвать ее.
Подобным образом можно через переменную вызывать функцию с параметрами и возвращать ее результат:
Функция как параметр функции
Поскольку функция в Python может представлять такое же значение как строка или число, соответственно мы можем передать ее в качестве параметра в другую функцию. Например, определим функцию, которая выводит на консоль результат некоторой операции:
В данном случае функция do_operation имеет три параметра, причем третий параметр, как предполагается, будет представлять функцию, которая принимает два параметра и возвращает некоторый результат. Иными словами третий параметр — operation представляет некоторую операцию, но на момент определения функции do_operation мы точно не знаем, что это будет за операция. Мы только знаем, что она принимает два параметр и возвращает какой-то результат, который потом выводится на консоль.
При вызове функции do_operation мы сможем передать в качестве третьего параметра другую функцию, например, функцию sum:
То есть в данном случае параметр operation фактически будет представлять функцию sum и будет возвращать сумму дву чисел.
Затем аналогичным образов в вызов функции do_operation можно передать третьему параметру другую функцию — multiply, которая выполнит умножение чисел:
Таким образом, более гибкие по функциональности функции, которые через параметры принимают другие функции.
Функция как результат функции
Также одна функция в Python может возвращать другую функцию. Например, определим функцию, которая в зависимости от значения параметра возвращает ту или иную операцию:
В данном случае функция select_operation в зависимости от значения параметра choice возвращает одну из трех функций — sum, subtract и multiply. Затем мы мы можем получить результат функции select_operation в переменную operation:
Так, в данном случае в функцию select_operation передается число 1, соответственно она будет возвращать функцию sum. Поэтому переменная operation фактически будет указывать на функцию sum, которая выполняет сложение двух чисел:
Замыкания в Python
Python позволяет определять функции внутри других функций. «Внутренняя» функция называется вложенной. Вот пример:
В этом примере мы объявили функцию display() внутри функции say() . Функция display() — вложенная.
При этом в функции display() используется переменная greeting , которая инициализирована вне этой функции, то есть из нелокальной области видимости.
В Python такие переменные как greeting называются свободными переменными.
На самом деле функция display() состоит из двух частей:
- Сама функция display() .
- Переменная greeting , в которой содержится значение «Привет» .
Так вот все вместе это называется замыканием (closure).
Замыкание (closure) — это вложенная функция, которая ссылается на одну или более переменных из объемлющей (enclosing) области видимости.
Можно вернуть функцию из функции
В Python функция может возвращать другую функцию. Например, так:
В этом примере функция say() возвращает функцию display() , а не выполняет ее.
Когда say() возвращает display() , на самом деле возвращается замыкание:
Следующая инструкция присваивает возвращаемое значение функции say() переменной fn . Поскольку fn — это функция, ее можно вызвать:
Функция say() выполняется и возвращает функцию fn() . Когда выполняется fn() , функция say() уже завершила выполнение.
Это значит, что область видимости функции say() уже не существует к тому моменту, когда выполняется fn() .
Поскольку переменная greeting принадлежит области видимости функции say() , она, по идеи, тоже должна уничтожаться после выполнения say() .
Однако fn() все равно как-то выводит значение переменной greeting , как вы видите в примере выше.
Разберемся, как это работает и почему так происходит.
Ячейки и переменные с несколькими областями видимости
Переменная greeting «разделяется» между двумя областями видимости:
- Функции say() .
- Замыкания.
То есть greeting находится одновременно в двух областях видимости. Тем не менее, она всегда ссылается на один и тот же строковый объект «Привет» .
Для этого Python создает промежуточный объект — ячейку (cell).
Узнать адрес ячейки в памяти можно через свойство __closure__ , как показано ниже:
Вывод
__closure__ возвращает кортеж ячеек.
В этом примере адрес ячейки в памяти — 0x0000017184915C40 . Она ссылается на строковый объект по адресу 0x0000017186A829B0 .
Если вы отобразите адрес памяти строкового объекта в функции say() и замыкании, то увидите, что они ссылаются на один и тот же объект в памяти:
Вывод
Когда вы обращаетесь к значению переменной greeting , Python технически дважды «прыгает» в память, чтобы получить значение строки.
Это объясняет, почему когда область видимости функции say() уже не существовала, вы все равно могли обратиться к строковому объекту, на который ссылается переменная greeting .
На основе этого механизма можно определить замыкание по-другому:
Замыкание — это функция и расширенная область видимости, в которой содержатся свободные переменные.
Чтобы узнать, какие свободные переменные содержатся в замыкание, можно использовать __code__.co_freevars . Например:
В этом примере fn.__code__.co_freevars вернет переменную greeting — единственную свободную переменную в замыкании fn .
Когда Python сам создает замыкания
Python создает новую область видимости каждый раз, когда выполняется функция. Если функция создает замыкание, Python тоже создаст новое замыкание. Рассмотрите следующий пример:
1. Сначала определим функцию multiplier() , которая возвращает замыкание:
Функция multiplier() возвращает произведение двух аргументов. Но возвращается не само произведение, а замыкание.
2. Теперь вызовем функцию multiplier() три раза:
Вызовы функция создадут три замыкания. Каждая функция умножает число на 1, 2, и 3 соответсвенно.
3. А теперь выполним функции замыканий:
Вывод
Как вы видите, у m1 , m2 и m3 разные инстансы замыкания.
Замыкания и цикл for
Предположим, что нам нужно создать все три вышеуказанные замыкания одновременно. Это можно сделать, например, так:
Что мы здесь делаем
- Объявляем список, в котором будем хранить замыкания.
- Используем лямбда-выражение, чтобы создать замыкание, и добавляем его в список на каждой итерации.
- «Распоковываем» замыкания из списка и присваиваем их переменным m1 , m2 и m3 соответсвенно.
- Передаем значения 10, 20 и 30 в каждое замыкание и выполняем их.
Вывод
Работает не так, как мы ожидали. Почему?
В цикле for x меняет значения от 1 до 3. Когда цикл завершается, значение x — 3.
Каждый элемент списка — соответсвующее замыкание lambda y: x*y .
Python использует значение x для вычислений каждый раз, когда вы вызываются m1(1) , m2(10) и m3(10) . И поскольку в момент выполнения замыкания x всегда 3, результат всех замыканий одинаковый — 30.
Чтобы исправить эту проблему, нужно объяснить Python, что значение x для вычислений нужно использовать в цикле.
Как в функции сослаться на переменную другой функции?
Python 3. PyQt4
Условная модель вопроса:
Есть функция «аа» с переменными. Я хочу в функции «bb» использовать эти переменные вот так:
Обе функции принадлежат классу QWidget.
В реале мой вопрос выглядит так:
Т.е. во второй функции надо воспользоваться переменной из первой функции — кат_index
- Вопрос задан более трёх лет назад
- 2358 просмотров
Оценить 6 комментариев
- Вконтакте

кириллица в имени переменной





В такой форме — никак.
Переменные, объявленные внутри функции, существуют только для этой функции и только на время её выполнения.
Соответственно, нужно либо объявление переменных вынести за пределы функции — в какое-то пространство имён, общее для обеих функций. Либо возвращать переменные в качестве результата функции, и вызывать эту функцию, чтобы получить её результат.
5 важных аспектов замыканий в Python
![]()
Замыкания не являются уникальным явлением Python и встречаются во многих других языках. При этом несмотря на то, что большинство начинающих разработчиков об этой концепции слышали, они не знают, что конкретно они из себя представляют и как используются. В данной статье я подчеркну наиболее важную информацию о замыканиях в Python, чтобы упростить для вас их освоение.
1. Внутренние и внешние функции
Как я уже отмечал, замыкания есть во многих языках программирования, а в Википедии им дано следующее определение:
“В языках программирования замыкание, также называемое лексическим замыканием или функциональным замыканием, представляет технику, используемую для реализации привязки имен, ограниченных лексическим контекстом, в языке с полноправными функциями”.
Это определение для многих покажется слишком техническим и не относится конкретно к Python. Чтобы помочь вам понять этот принцип, я выражу его более просто: замыкание — это внутренняя функция, создаваемая во внешней функции и использующая ее переменные. Она возвращается внешней функцией в виде ее выходного значения. Не слишком технически? Думаю, слишком. Лучше всего показать на примере. Начнем со следующего фрагмента кода.
Multiplier creator:
В этом коде double multiplier и triple_multiplier представляют два замыкания, так как соответствуют их определению:
- multipler является внутренней функцией, созданной внутри multiplier_creator , которая называется внешней функцией, поскольку находится вне multiplier . Внутренняя функция зачастую зовется вложенной, так как, по сути, вкладывается в другую функцию.
- Созданная внутренняя функция представляет значение, возвращаемое внешней функцией. Стоит отметить, что multiplier_creator возвращает multiplier непосредственно вместо выходного значения функции multiplier .
- multiplier использует переменную n , являющуюся параметром multiplier_creator . Доступ внутренней функции к внешним переменным называется нелокальной привязкой переменных.
Привязка нелокальных переменных является, пожалуй, наиболее мутной частью темы замыканий. Именно этот процесс мы и разберем далее.
2. Локальные и нелокальные переменные
При работе с функциями мы знаем, что внутри них можно использовать любые передаваемые параметры, которые называются локальными переменными. По существу, функция формирует локальную область видимости, ограничивающую доступ к ее переменным.
Что же касается примера выше, то в нем функция multiplier_creator определяет локальную область видимости, а параметр n является локальной переменной. Аналогичным образом внутренняя функция multiplier определяет еще одну внутреннюю область, где локальной переменной выступает параметр number . При этом стоит заметить, что функция multiplier также использует параметр n . Несмотря на то, что n является локальной переменной для области multiplier_creator , для multiplier она нелокальная. Таким образом, в этом примере функция multiplier использует нелокальную переменную, также известную как свободная переменная.
Помимо отличия между локальными и нелокальными переменными, некоторые из вас могли слышать о глобальных переменных, которые определяются на уровне модуля. В этом случае обычно фигурируют такие термины, как глобальная и встроенная области.
Как вы могли заметить, то с позиции внутренней функции мы называем процесс обращения к локальным переменным внешней функции привязкой нелокальных переменных. Использование слова “привязка” в этом случае примечательно. Что конкретно оно значит? Разберем это далее.
3. Привязка нелокальных переменных
Привязка нелокальных переменных в ряде других языков называется захватом нелокальных переменных, что передает характеристику замыканий. Можно просто представить себе этот процесс как “владение” используемыми нелокальными переменными внутренней функцией. Рассмотрим это на примере:
В этом коде мы удаляем внешнюю функцию multiplier_creator , в результате чего она становится недоступной. Но обратите внимание, что замыкания (т.е. double_multiplier и triple_multiplier ) используют параметр n , принадлежащий удаляемой multiplier_creator . В итоге можно подумать, что замыкания перестанут работать. Однако они по-прежнему выдают ожидаемый результат.
Причина в том, что замыкания уже установили привязку нелокальной переменной, которую используют. Иначе говоря, у них есть копия этой привязанной переменной. Чтобы пронаблюдать эту особенность, рассмотрим несколько специальных проверочных функций:
__code__.co_freevars позволяет проверить имя привязки нелокальной переменной для замыканий, а __closure__[0].cell_contents уточняет значение привязанной нелокальной переменной. Вам не обязательно знать подробности этих функций, так как они являются просто внутренними реализациями.
Эту информацию важно знать, потому что замыкания получают собственные копии нелокальных переменных путем привязки, что позволяет им продолжать работать даже после удаления внешней функции.
4. Ключевое слово Nonlocal и исключение Unboundlocalerror
При создании замыканий программисты иногда получают исключение UnboundLocalError . Разберем на примере:
На первый взгляд функция running_total_multiplier_creator выглядит подходящей для генерации замыкания. Однако при использовании получившегося замыкания возникает исключение UnvoundLocalError . Что означает это исключение? Если прочесть сообщение Traceback, то станет ясно, что проблема заключается в коде running_total += product . Почему он вызывает подобную ошибку? Вот объяснение:
- Эта строка кода, по сути, интерпретируется как running_total = running_total + product .
- Порядок поиска переменной определяется правилом LEGB, что соответствует последовательности локальная->замыкающая->глобальная->встроенная. При выполнении running_total = xxx во внутренней функции мы регистрируем локальную переменную в локальной области этой функции. Когда Python продолжает выполнять код справа от инструкции присваивания, он снова встречает переменную running_total , в связи с чем начинает искать эту переменную и находит ее в локальной области. Однако он замечает, что ей не было присвоено какое-либо значение, потому что инструкция присваивания не закончила свое выполнение. Именно поэтому сообщение об ошибке гласит: local variable ‘running_total’ referenced before assignment . Когда обращение к переменной происходит до момента присваивания ей значения, это называется ошибкой отсутствия привязки (unbound error).
Если вернуться назад и взглянуть на функцию multiplier , то станет видно, что мы хотели использовать переменную tunning_total , определенную в области running_total_multiplier_creator , с позиции функции multiplier называемую замыкающей областью. Для того, чтобы внутренняя функция поняла, что running_total не задумывалась как локальная переменная, нужно заявить об этом с помощью ключевого слова nonlocal . Вот исправленный вариант:
Как видите, мы просто объявили, что running_total является нелокальной переменной, указав Python обходить локальную область при поиске переменной running_total .
5. Почему замыкания?
Мы рассмотрели, чем являются замыкания, но вас может заинтересовать, зачем вообще они нужны? Одно из наиболее распространенных применений состоит в создании функций-декораторов. Несмотря на то, что замыкания вы можете и не знать, я уверен, что о декораторах вы слышали наверняка. В Python декораторы — это функции, которые изменяют поведение других функций, не влияя на их алгоритмы.
Функция simple_logger является декоратором, использование которого подразумевает наличие перед именем символа @ и размещение самого его над декорируемой функцией. При вызове функции hello_world произойдет следующее:
Суть в том, что декорированная функция по факту является замыканием. В процессе декорации внутренне происходит два этапа:
Чтобы убедиться в том, что hello_world действительно является замыканием, можно снова выполнить проверку:
- Декорированная функция hello_world содержит нелокальную переменную func .
- Привязанное значение является функцией. При этом также важно знать, что функции в Python — это просто регулярные объекты, а значит их можно рассматривать как переменные других моделей данных (например, списки и словари).
Заключение
В этой статье мы рассмотрели пять наиболее важных аспектов замыканий. Вот их краткий обзор: