Затваряния в Python

Под затваряне (closure) се разбира функция заедно с всички външни променливи, до които тя има достъп.

В Python най-често, като се казва "затваряне на функция", се има предвид не самата функция, а именно нейните външни променливи.

Нека имаме следната функция outer, в която е декларирана променлива i и вътрешна функция inner. В нея към i ще се добавя единица. За да работи променливата i коректно, добавяме към нея инструкцията nonlocal:

pythondef outer():
  i = 0
  def inner():
    nonlocal i
    i += 1
    print(i)
  
  return inner

Сега нека сложим външната функция в променлива res и я извикаме със кръгли скоби:

pythonres = outer()
res() # ще изведе 1

Нека извикаме res няколко пъти. След изпълнение на кода всеки път броячът i ще се увеличава с единица:

pythonres() # ще изведе 2
res() # ще изведе 3
res() # ще изведе 4

Въпреки това, тук има важен нюанс - всяко извикване на функцията outer ще увеличава своя брояч. Нека първото извикване на outer запишем в променлива res1, а второто извикване - в променлива res2. След това последователно ги извеждаме в конзолата:

pythonres1 = outer()
res1() # ще изведе 1
res1() # ще изведе 2
res1() # ще изведе 3

res2 = outer()
res2() # ще изведе 1
res2() # ще изведе 2
res2() # ще изведе 3
Задание 1

Даден е следният код:

pythondef outer():
  i = 10

  def inner():
    nonlocal i
    i -= 2
    print(i)
  return inner
  
res1 = outer()
res1()
res1()

res2 = outer()
res2()
res2()
res2()

Кажете какво ще се изведе в конзолата.

Задание 2

Направете функция, всяко извикване на която ще връща следващото число на Фибоначи.

Задание 3

Направете функция, която ще дава случайно цяло число в интервал, но така, че да няма еднакви две последователни пъти.