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

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

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

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

Определение внутренней функции

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

def function1(): # outer function
    print ("Hello from outer function")
    def function2(): # inner function
        print ("Hello from inner function")
    function2()

function1()

Вывод:

Hello from outer function
Hello from inner function

В приведенном выше примере функция function2() была определена внутри function1(), что сделало ее внутренней функцией. Чтобы вызвать функцию2(), мы должны сначала вызвать функцию1(). Затем function1() продолжит работу и вызовет функцию function2(), как она была определена внутри нее.

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

def function1(): # outer function
    print ("Hello from outer function")
    def function2(): # inner function
        print ("Hello from inner function")
    function2()

При выполнении код ничего не вернет.

Вот еще один пример:

def num1(x):
   def num2(y):
      return x * y
   return num2
res = num1(10)

print(res(5))

Вывод:

50

Код возвращает умножение двух чисел, то есть 10 и 5. Пример показывает, что внутренняя функция может обращаться к переменным, доступным во внешней функции.

До сих пор вы видели, что мы можем получить доступ к переменным внешней функции внутри внутренней. Что, если мы попытаемся изменить переменные внешней функции изнутри внутренней? Посмотрим, что происходит:

def function1(): # outer function
    x = 2 # A variable defined within the outer function
    def function2(a): # inner function
       # Let's define a new variable within the inner function
       # rather than changing the value of x of the outer function
        x = 6
        print (a+x)
    print (x) # to display the value of x of the outer function
    function2(3)

function1()

Вывод:

2
9

Выходные данные показывают, что мы можем отображать значение переменной, определенной во внешней функции из внутренней, но не изменять его. Оператор x = 6 помог нам создать новую переменную x внутри внутренней function2() вместо того, чтобы изменять значение переменной x, определенной во внешней функции function1().

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

Зачем использовать?

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

def outer_function(x):
    # Hidden from the outer code
    def inner_increment(x):
        return x + 2
    y = inner_increment(x)
    print(x, y)

inner_increment(5)
#outer_function(5)

Вывод:

Traceback (most recent call last):
  File "C:/Users/admin/inner.py", line 7, in <module>
    inner_increment(5)
NameError: name 'inner_increment' is not defined

В приведенном выше коде мы пытаемся вызвать функцию inner_increment(), но вместо этого получили ошибку.

Теперь закомментируйте вызов inner_increment() и раскомментируйте вызов external_function(), как показано ниже:

def outer_function(x):
    # Hidden from the outer code
    def inner_increment(x):
        return x + 2
    y = inner_increment(x)
    print(x, y)

#inner_increment(5)
outer_function(5)

Вывод:

5 7

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

Закрытие и заводские функции

Все примеры, которые мы видели до сих пор, содержат просто обычные функции, которые были вложены в другие функции. Мы можем написать такие функции по-другому, вместо того, чтобы вкладывать их в другие функции. У нас нет конкретной причины, почему мы должны их вкладывать.

Однако в случае замыканий необходимо использовать вложенные функции.

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

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

Ниже приведены условия, которые необходимо выполнить для создания замыкания в Python:

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

Рассмотрим следующий пример:

def function1(name):
    def function2():
        print('Hello ' + name)
    return function2

func = function1('Nicholas')
func()

Вывод:

Hello Nicholas

Приведенный выше код демонстрирует, что с помощью замыканий мы можем сгенерировать и вызвать функцию из-за пределов ее области посредством передачи функции. Объем функции function2() находится только внутри function1(). Однако с помощью замыканий у нас появилась возможность расширить эту область видимости и вызвать ее извне.

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

def power_generator(num):

    # Create the inner function
    def power_n(power):
        return num ** power

    return power_n

power_two = power_generator(2)
power_three = power_generator(3)
print(power_two(8))
print(power_three(4))

Вывод:

256
81

В приведенном выше скрипте из функции power_n (power) мы создали два других объекта, power_two и power_three. Это делает power_n (power) фабричной функцией, поскольку она генерирует для нас функции power_two и power_three, используя переданный нами параметр.

Заключение

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

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *