A quick word about closures in Python

  • 2020-05-17 05:48:38
  • OfStack

Closures in Python

Someone left a message about one of them the other day 闭包 and re.sub The use of. I did a search on this site and found that I had not written anything about closures, so I decided to summarize 1 and improve the content of Python.

1. The concept of closures

Let's start with the basics. What are closures? Here's the wiki explanation:

 In computer science, closures (Closure) It's a lexical closure (Lexical Closure) Is a function that refers to a free variable. This referenced free variable is going to be equal to this function 1 Co-existence is no exception even if it has left the environment in which it was created. So, there's another 1 It is said that a closure is an entity composed of a function and its associated reference environment. Closures can have multiple instances at run time, and different reference environments and the same combination of functions can produce different instances. 
....

Two key points were mentioned above: free variables and functions, which we'll talk about later. It can be figuratively understood as a closed package, which is a function. Of course, there is also the logic corresponding to the function inside. The things inside the package are free variables, which can wander around with the package. And, of course, the premise is that the package was created.

Under introduction 1 via Python, a closure is when you call a function A, and the function A returns a function B to you. This function, B, is called a closure. The arguments you pass when you call the function A are free variables.

Here's an example:


def func(name):
 def inner_func(age):
  print 'name:', name, 'age:', age
 return inner_func

bb = func('the5fire')
bb(26) # >>> name: the5fire age: 26

When func is called, a closure -- inner_func -- is generated, and the closure holds the free variable -- name, so this also means that when the function func's life cycle ends, the variable name will still exist because it is referenced by the closure and will not be recycled.

Another point is that closures are not unique to Python. All languages that have citizens such as functions as 1 have closures. Closures can also be used in a citizen language like Java, which USES class as 1, but it has to be implemented in a class or interface.

More conceptual stuff can be found in the reference link at the end.

2. Why use closures

Based on the introduction above, I don't know if the reader feels that this thing is similar to the class. The similarity is that they both provide encapsulation of the data. The difference is that the closure itself is a method. Like class 1, we often abstract generic things into classes (and, of course, real-world business modeling) in order to reuse generic functionality. Closures are also a good choice when we need abstractions of function granularity.

At this point a closure can be understood as a read-only object to which you can pass a property, but which can only give you an interface to execute. Therefore, in the program, we often need such a function object -- closure -- to help us accomplish a common function, such as the decorator, which will be mentioned later.

Use closures

The first scenario, which is very important and common in python, is decorator. Python provides a friendly "grammatical sugar" -- @ for decorator, so that we can use the decorator conveniently. The principle of decoration is not elaborated too much, in short, you add @decorator_func to a function func, which is equivalent to decorator_func(func):


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 the decorator example, the closure (wrapper) holds the external func parameter and is able to accept the external passed parameter, which is passed intact to func and returns the execution result.

This is a simple example, a little more complex, that can have multiple closures, such as the frequently used decorator for LRUCache, which can accept the parameter @lru_cache (expire=500). The implementation is a nest of two closures:


def lru_cache(expire=5):
 #  The default 5s timeout 
 def func_wrapper(func):
  def inner(*args, **kwargs):
   # cache  To deal with  bala bala bala
   return func(*args, **kwargs)
  return inner
 return func_wrapper

@lru_cache(expire=10*60)
def get(request, pk)
 #  Omit the code 
 return response()

Those of you who don't know much about closures should be able to understand the code above, which is one of the most common interview questions we've asked in previous interviews.

The second scenario is based on a feature of closures called lazy evaluation. This application is more common when database access, such as:


#  Pseudocode notation 

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 the database access is performed 

The above somewhat inappropriate example shows the ability to perform lazy evaluation with closures, but the result query returns is not a function, but a class that functions. If you're interested, check out Django's implementation of queryset, which works in a similar way.

The third scenario, where you need to pre-assign a parameter to a function, of course, has a good solution for accessing functools.parial in Python, but you can do it with closures.


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 with functools It's a lot easier than that 
#  Only need to:  functools.partial(say, age=15)(name='the5fire')

This seems like another far-fetched example, but it's also a practical application of closures.

In conclusion, closures are easy to understand and are widely used in Python. This article is a summary of closures. If you have any questions, please feel free to leave a comment.

4. References

Wikipedia - closures

http://stackoverflow.com/questions/4020419/closures-in-python

http://www.shutupandship.com/2012/01/python-closures-explained.html

http://stackoverflow.com/questions/141642/what-limitations-have-closures-in-python-compared-to-language-x-closures

http://mrevelle.blogspot.com/2006/10/closure-on-closures.html


Related articles: