There is some code:

def aaa(): t = "text" def bbb(): print(t) return bbb v = aaa() v() 

In the body of the function aaa, the function bbb is created and it is returned. I can not understand 2 moments: 1. Why the call V () does not cause an error, because the object of the function must be destroyed after leaving the body. 2. Why is the variable t = "text" not destroyed? The reason is the same because

  • Nobody should be destroyed, because with the def bbb() function you automatically created a closure and then placed this function in the variable v , so that both the function and the closure and the variable t in this closure were successfully saved - andreymal
  • Actually, the value of t can be detected stored in v.__closure__[0].cell_contents - andreymal
  • In the book that I read there is no word about the "Closure". What is it? - Sergey Patience
  • 2
    The function “remembers” the local namespace surrounding it, including the variable t in this namespace - this is the essence of the closure - andreymal 5:09

1 answer 1

An object is destroyed only when it ceases to be needed by someone else; in CPython this happens when the number of references to an object becomes zero.

v in this example, a closure that has access to both its names (in this example, they are not available), and to the names inside the function aaa (ie, t , bbb ), other more external functions (also not) to the global names relative to the place in which the function was declared (i.e. aaa , v )

A closure is a function that captures the variables of its originating function, or functions even higher in the hierarchy, and has the ability to work with them, even if that function has already completed.

Examples:

 def aaa(x): def bbb(y): def ccc(z): return x + y * z return ccc return bbb print(aaa(5)(6)(7)) # 47 
 def message(secret): def helper(): return f'Никто кроме меня не знает, что secret={secret!r}' return helper f1 = message("password") f2 = message("hack the internet") print(f1()) # Никто кроме меня не знает, что secret='password' print(f2()) # Никто кроме меня не знает, что secret='hack the internet' 
 def notinlist(lst): def helper(x): return x not in lst return helper print(*filter(notinlist([1,3]), range(10))) # 0 2 4 5 6 7 8 9 

And all the same, but with the help of anonymous "lambda" functions

 def aaa(x): return lambda y: lambda z: x + y * z 
 def notinlist(lst): return lambda x: x not in lst 
 def message(secret): return lambda: f'Никто кроме меня не знает, что secret={secret!r}' 
  • That is, as I understand the variable t is not destroyed because the bbb function refers to it, and the variable v refers to bb? - Sergey Patience
  • If it is oversimplified, then yes, moreover if there are other variables in aaa that bbb doesn’t care about - they may well die with the completion of aaa . And although this is not quite so in the implementation, it is easier to assume that each time you call aaa , a new instance of the bbb function is created that captures the actual data for this call from the higher context, as in my second example, f1 and f2 indicate different functions, who have access to different secret - extrn
  • Slightly corrected the answer, because the closure captures data not by reference but by name. - extrn 8:39 pm