Как вызвать функцию в функции python

от admin

Вызов функции из функции

Если Вам необходимо вызвать функцию test2 из глобальной области видимости, то это невозможно.
Она является локальным объектом функции test1 и доступна только в контексте исполнения этой функции.

Если же Вы хотите вызвать её в теле функции test1 , то это тривиально.

Пример:

Функцию test2 можно вызвать, если ее вернуть из первой функции. Типичный способ применения — создание «замыкания» (closure): test2 будет помнить состояние локальных переменных (в том числе аргументов) функции test1 .

insolor's user avatar

Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.3.11.43304

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Функции и методы в Python: передача функции в функцию. Декоратор

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

Что надо знать о методах и функциях в Python?

Говоря о функциях в Python, нужно упомянуть два аспекта: 1) функция в Python — есть объект специального вида, который можно передавать в виде аргумента другим функциям; 2) внутри функций в Python вы можете создавать другие функции, а также вызывать их, возвращая результат посредством return.

Теперь давайте поговорим об этом подробнее.

Функция как объект в Python

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

В нашем примере мы передали функции map в виде первого аргумента функцию sq. Последняя будет по очереди применяться ко всем элементам нашего списка a.

Кроме того, в Python функция является специальным объектом, имеющим метод __call__() . Представьте, что мы создали следующий класс:

Объект такого класса в Python мы сможем вызывать как функцию:

Функция внутри функции в Python

Функции в Python мы можем создавать, вызывать и возвращать из других функций. Кстати, на этом основана идея замыкания (closures) в Python.

Давайте создадим функцию, умножающую 2 числа:

В этой функции в Python реализованы два важных свойства: 1) внутри функции mul() мы создаём ещё одну функцию helper() ; 2) функция mul() возвращает нам функцию helper() в качестве результата работы.

Вызов этой функции в Python:

Особенность заключается в том, что мы можем создавать на базе функции mul() собственные кастомизированные функции. Давайте создадим функцию в Python, умножающую на 3:

В результате была построена функция three_mul() , умножающая на 3 любое переданное ей число.

Декоратор функции в Python

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

Создание

Представьте, что мы имеем пару простых функций в Python:

При этом мы желаем их дополнить таким образом, чтобы перед вызовом основного кода нашей функции печаталась строчка “Start function”, а в конце – строка “Stop function”.

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

Теперь поговорим о втором пути. Для начала создадим функцию:

Теперь нужно обернуть функции в оболочку:

Обратите внимание, что функции first_test и second_test не поменялись.

Наши функции second_test_wrapped и first_test_wrapped обладают функционалом, который нам и нужен.

Теперь, если надо, чтобы так работали функции с именами first_test и second_test, делаем следующее:

Выполненные нами действия и являются реализацией идеи декоратора.

Правда, вместо строк:

мы можем написать иначе:

В нашем случае @simple_decore – это не что иное, как декоратор функции.

Передаём аргументы в функцию с помощью декоратора

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

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

Теперь давайте выполним данную функцию с аргументом 4:

Декораторы для методов класса в Python

С декоратором можно объявлять и методы классов. Давайте выполним модификацию декоратора param_transfer:

Теперь приступим к созданию класса для представления 2-мерного вектора (математического). В классе определим метод norm() , выводящий модуль вектора.

Что же, осталось продемонстрировать работу нашего метода:

Возвращаем результат работы функции через декоратор

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

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

Замыкания в 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() .

Читать:
Display 1 no cameras rendering unity что делать

Поскольку переменная 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

Предположим, что нам нужно создать все три вышеуказанные замыкания одновременно. Это можно сделать, например, так:

Что мы здесь делаем

  1. Объявляем список, в котором будем хранить замыкания.
  2. Используем лямбда-выражение, чтобы создать замыкание, и добавляем его в список на каждой итерации.
  3. «Распоковываем» замыкания из списка и присваиваем их переменным m1 , m2 и m3 соответсвенно.
  4. Передаем значения 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

Перевод статьи подготовлен для студентов курса «Web-разработчик на Python». Интересно развиваться в данном направлении? Запишитесь на День Открытых Дверей курса и пообщайтесь вживую с преподавателем: онлайн-трансляция 23 июля в 20:00 по мск.!

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

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

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

Функции

Функции также называются объектами первого класса в Python. Функции это такие же значения, как числа, списки и строки, как видно из следующего примера.

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

Область видимости функции как переменная

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

Время жизни переменной

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

Вложенные функции

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

Декораторы

Замыкание (closure), которое принимает функцию в качестве параметра и возвращает функцию, называется декоратором. Рассмотрим пример полезных декораторов.

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

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

Похожие статьи