Detailed Explanation of the Example of python Closure

  • 2021-12-09 09:10:17
  • OfStack

1. Define internal functions in external functions, and internal functions include accessing external functions. Even after the life cycle of the external function ends, the internal function can still access the external function variables.

2. The return value of the external function is the internal function itself.

Instances


def outer():
    cheer = 'hello '
    def inner(name):
        return cheer + name
    return inner
if __name__ == "__main__":
    # Output hello kevin
    print(outer()('kevin'))

Extension of knowledge points:

The Concept of Closure

We try to understand the lower closure of 1 conceptually.
In some languages, when another function can be (nested) defined in a function, closures may occur if the inner function references the variables of the outer function. Closures can be used to create an association between a function and a set of "private" variables. These private variables can remain persistent during multiple calls to a given function.
In easy-to-understand words, when a function is returned as an object, it carries external variables and forms a closure. Look at the following example:


def make_printer(msg):
  def printer():
    print(msg) #  Entrainment of illicit goods (external variable) 
 
  return printer #  Returns a function, a function with private goods 
 
 
printer = make_printer("Foo!")
printer()

Programming languages that support functions as objects, 1 generally support closures. For example, python and JavaScript.

How to understand closures

What's the point of having closures? Why do you need closures

Personally, I think the point of closure is that it carries external variables (private goods). If it does not carry private goods, it is no different from ordinary functions. The same function carries different private goods, so it realizes different functions. In fact, you can also understand that closures are very similar to the concept of interface-oriented programming, and closures can be understood as lightweight interface programming.

Interface defines a set of constraint rules for method signature.


def tag(tag_name):
  def add_tag(content):
    return "<{0}>{1}</{0}>".format(tag_name, content)
  return add_tag
 
content = "Hello"
 
add_tag = tag('a')
print(add_tag(content)) # <a>Hello</a>
 
add_tag = tag('b')
print(add_tag(content)) # <b>Hello</b>

In this example, we want to add tag function to content, but the specific tag_name should be determined according to the actual demand, and the interface for external call has been determined, that is, add_tag (content). If we implement it in an interface-oriented way, we will first write add_tag as an interface, specify its function and return type, and then implement add_tag of a and b respectively.

However, in the concept of closure, add_tag is a function, which requires two parameters, tag_name and content, except that tag_name is packaged and taken away. So 1 can tell me how to pack it at the beginning, and then take it away.

The above example is not very vivid. In fact, the concept of closure is very common in our life and work. For example, when dialing a mobile phone, you only care about who the phone is called, but don't worry about how each brand of mobile phone is realized and which modules are used. For example, when you go to a restaurant, you can enjoy the service as long as you pay. You don't know how much gutter oil is used in that table. These can all be seen as closures, which return functions or services (phone calls, meals), but these functions use external variables (antennas, gutter oil, etc.)

You can also think of a class instance as a closure. When you construct this class, you use different parameters. These parameters are the packages in the closure, and the methods provided by this class are the functions of the closure. But classes are much larger than closures, because closures are only a function that can be executed, but class instances may provide many methods.

When to use closures

Closures are very common in python, but you don't notice that this is a closure. For example, the decorator Decorator in python, if you need to write a decorator with parameters, then 1 will generally generate closures.

Why? Because the decorator of python is a fixed function interface form. It requires that your decorator function (or decorator class) must accept 1 function and return 1 function:


# how to define
def wrapper(func1): #  Accept 1 A callable Object 
  return func1 #  Return 1 Objects, 1 General function 
 
 
# how to use
def target_func(args): #  Objective function 
  pass
 
 
#  Calling mode 1 , direct package 
result = wrapper(target_func("123"))
 
#  Calling mode 2 , using @ Grammar, equivalent mode 1
@wrapper
def target_func(args):
  pass
 
result = target_func()

What if your decorator has parameters? Then you need to pack another layer on the original decorator to receive these parameters. After these parameters (private goods) are passed to the inner decorator, the closure is formed. Therefore, when your decorator needs custom parameters, 1 will generally form closures (except class decorators)


def html_tags(tag_name):
  def wrapper_(func):
    def wrapper(*args, **kwargs):
      content = func(*args, **kwargs)
      return "<{tag}>{content}</{tag}>".format(tag=tag_name, content=content)
    return wrapper
  return wrapper_
 
 
@html_tags('a')
def hello(name='Toby'):
  return "Hello {}!".format(name)
 
 
#  No need @ The writing style of 
# hello = html_tags('b')(hello)
# html_tags('b')  Yes 1 Closure that accepts 1 Function and returns 1 Functions 
 
print(hello()) # <a>Hello Toby!</a>
print(hello("world")) # <a>Hello world!</a>

Related articles: