before , We are introducing java8 Newly added lambda When the expression , I once introduced “ Closure ” The concept of .
So-called “ Closure ”, A code block that can contain free variables , The free variables contained in the code block are not bound to any objects at the time of definition , Nor are they defined within this code block or in any global context , It is a local variable defined in the context of a code block . In a nutshell , A closure is a separate block of code , But it can access non global variables outside its definition body . Many languages implement closure features through anonymous functions , The famous lambda An expression is a typical example of a closure . python There is good support for closures .
Suppose we have a way , Each call outputs a history of the total average number of parameters passed in by all calls :
>>> avg(10)
10
>>> avg(11)
10.5
>>> avg(39)
20
How can we achieve it ? Here is an example of a closure :
>>> def make_average():
... series = []
... def avg(value):
... series.append(value)
... return sum(series)/len(series)
... return avg
...
>>> avg = make_average()
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(39)
20.0
stay avg = make_average() After statement execution ,make_average The stack space of the method will be destroyed , Defined in its stack space series Variables should follow make_average Method is destroyed at the end of its execution . But what's surprising is , thereafter avg Method is executed without error , It's internal to series There is no error in adding the list , that series Where exactly are variables defined ? We have previously introduced python Scope of action , It says Enclosing Scope ( The outer layer of a nested function, the inner part of a function ) — Nested scope ( Closure ) python Namespace and scope of
When python When the interpreter sees that the external local variable is used inside the nested function , The interpreter will mark it as a free variable , It will not be destroyed with the local scope .
In the above example, we further modify :
>>> def make_average():
... count = total = 0
... def avg(value):
... count += 1
... total += value
... return total / count
... return avg
...
>>> avg = make_average()
>>> avg(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in avg
UnboundLocalError: local variable 'count' referenced before assignment
It seems that this example is no different from the closure example above , He will be series The variable is changed to save the sum and the number of calls , But it is wrong to call , Because the outside count And total With make_average Method is destroyed at the end of the call , Why is that ? When the interpreter sees avg Function , Yes count And total Both variables have assignment behavior , So they were treated as avg Method variables in the local scope , Not a free variable , Then the two external local variables are destroyed normally . python3 Introduced nonlocal keyword , To solve such a problem :
>>> def make_average():
... count = total = 0
... def avg(value):
... nonlocal count, total
... count += 1
... total += value
... return total / count
... return avg
...
>>> avg = make_average()
>>> avg(10)
10
>>> avg(11)
10.5
>>> avg(39)
20
>>> class Average:
... def __init__(self):
... self.series = []
... def __call__(self, value):
... self.series.append(value)
... return sum(self.series)/len(self.series)
...
>>> avg = Average()
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(39)
20.0
This example implements the encapsulation of historical call information through classes , And pass __call__ Method implements the computation logic . Generally speaking , All the functions that closures can implement can be implemented by classes , Classes are often the easiest solution to think of , that , Where are the advantages of closures ? stay python in , The most important use of closures is in decorators , that , What is the decorator ? What kind of sparks can be generated by the combination of closures and decorators ? We will have an article about the use and principle of decorators in detail , Coming soon .