A few days ago someone in my article Python project exercise one: Instant tag message, about one of the closures and the use of re.sub is not clear. I searched on my blog and found that I hadn't written anything about closures, so I decided to summarize the content of Python on my blog.
1. The concept of closures
First of all, from the basic concept, what is closure? Take a look at the wiki explanation:
Copy Code code as follows:
In computer science, closures (Closure) are abbreviations for lexical closures (lexical Closure), which are functions that refer to free variables. The referenced free variable will exist with this function, even if it has left the environment that created it. So, there is another saying that closures are entities that are combined by functions and reference environments associated with them. Closures can have multiple instances at run time, and different reference environments and the same combination of functions can produce different instances.
....
The above mentioned two key places: free variables and functions, these two key points later. Still have to repeat the meaning of "closure", Wang Wen know the meaning, can be image of it as a closed package, this package is a function, of course, there is a function of the internal corresponding logic, the package inside the thing is a free variable, free variable can be wandering around with the package. Of course, there must be a premise that this package was created.
In the language of Python, a closure is where you call a function A, and this function a returns a function B to you. The return function B is called a closure. The argument you pass when you call function A is a free variable.
As an example:
Copy Code code as follows:
def func (name):
def inner_func (age):
print ' name: ', Name, ' Age: ', age
Return Inner_func
bb = func (' The5fire ')
BB (+) # >>> Name:the5fire age:26
This is when the call to Func produces a closure--inner_func, and the closure holds the free variable--name, so it also means that when the function func lifecycle is over, the name variable still exists because it is referenced by the closure and is not recycled.
In addition, closures are not a unique concept in Python, and all languages that function as first-class citizens have the concept of closures. However, a closure can also be used in a language like Java for class-class citizens, but it has to be implemented with classes or interfaces.
More conceptual things can refer to the final reference link.
2. Why use closures
Based on the above introduction, I do not know whether the reader has a feeling that this thing is similar to the class, the similarity is that they all provide a package of data. The difference is that the closure itself is a method. Like classes, we often abstract common things into classes in programming, (and, of course, modeling the real world-business) to reuse common functionality. Closures are also the same, and when we need the abstraction of function granularity, closures are a good choice.
At this point the closure can be understood as a read-only object, and you can pass a property to him, but it can only provide you with an executing interface. So in the program we often need such a function object--closure, to help us complete a common function, such as the later mentioned--adorners.
3. Using closures
The first scenario, one of the most important and common use scenarios in Python, is the adorner, which provides a friendly "syntactic sugar"--@ for the adorner, making it easy to use the adorner, and the principle of decoration is not overly elaborate, In short, you add @decorator_func to a function func, which is equivalent to Decorator_func (func):
Copy Code code as follows:
def decorator_func (func):
def wrapper (*args, **kwargs):
return func (*args, **kwargs)
Return wrapper
@decorator_func
def func (name):
print ' My name is ', name
# is equivalent to
Decorator_func (func)
In this example of the adorner, the closure (wrapper) holds the external func parameter and is able to accept the externally transmitted parameters, and the accepted parameters are passed back to the Func, and the execution results are returned.
This is a simple example of a slightly more complex point where you can have multiple closures, such as the LRUCache adorner that you use frequently, and you can accept parameters @lru_cache (expire=500) on the adorner. The implementation is the nesting of two closures:
Copy Code code as follows:
def lru_cache (expire=5):
# Default 5s Timeout
def func_wrapper (func):
def inner (*args, **kwargs):
# Cache Processing Bala Bala Bala
return func (*args, **kwargs)
return inner
Return Func_wrapper
@lru_cache (EXPIRE=10*60)
def get (request, PK)
# Omit specific code
return response ()
Students who do not understand the closure must be able to understand the above code, this is the interview we have often asked the face questions.
The second scenario is an attribute based on closures-"lazy evaluation". This application is more common in the database access, such as:
Copy Code code as follows:
# Pseudo Code Signal
Class QuerySet (object):
def __init__ (self, SQL):
Self.sql = sql
Self.db = Mysql.connect (). Corsor () # Pseudo code
def __call__ (self):
Return Db.execute (Self.sql)
def query (SQL):
return QuerySet (SQL)
result = Query (' Select name from User_app ')
If time > Now:
Print result # This is when database access is performed
This less-than-appropriate example shows the ability to perform lazy evaluation through closures, but the result from query above is not a function, but a class with functional functions. Interested to see the implementation of the Django Queryset, the principle is similar.
The third scenario, which requires an early assignment of the parameters of a function, certainly has a good solution to access functools.parial in Python, but it can be done with closures.
Copy Code code as follows:
def partial (**outer_kwargs):
def wrapper (func):
def inner (*args, **kwargs):
For K, v. in Outer_kwargs.items ():
Kwargs[k] = V
return func (*args, **kwargs)
return inner
Return wrapper
@partial (age=15)
Def say (Name=none, Age=none):
Print name, age
Say (name= "The5fire")
# Of course it's a lot easier to use functools than that.
# only need: Functools.partial (say, age=15) (name= ' The5fire ')
It seems to be a far-fetched example, but it's also a practice of closures.
Finally, the closure of this thing is easy to understand, the application in Python is also very extensive, this article is a summary of closures, there are any questions welcome to the message exchange.