Рубрики
Без рубрики

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

Автор оригинала: Nicholas Samuel.

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

Что такое вложенная функция?

Функции являются одним из “первоклассных граждан” Python, что означает, что функции находятся на том же уровне, что и другие объекты 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

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

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

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 помог нам создать новую переменную x внутри внутренней функции function 2() вместо изменения значения переменной 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 
    inner_increment(5)
NameError: name 'inner_increment' is not defined

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

Теперь закомментируйте вызов inner_increment() и раскомментируйте вызов outer_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 внешней функции. Другими словами, переменные внутри внутренней функции недоступны вне ее. В таком дизайне есть большое преимущество. После проверки всех аргументов во внешней функции мы можем спокойно пропустить проверку ошибок во внутренней функции.

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

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

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

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

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

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

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

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

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

func = function1('Nicholas')
func()

Выход

Hello Nicholas

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

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

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.