closure
Definition
-
Closed is a closed (function in a function) and a package is a inclusion (the internal function refers to variables in the scope of an external function rather than in the global scope).
-
What is closure
- The Reference of Internal Functions to Variables in the Scope of External Functions
- The attributes in a function have a life cycle (during the execution of the function)
- Closure functions within closures privatize variables and complete data encapsulation, similar to object-oriented
Introduce
def foo(): print("in foo()") def bar(): print("in bar()") #1. Running internal functions directly to report errors #bar() #2. Consider running external functions first and then internal functions, which will still report errors, and the resources will be released after the external functions are finished running. #foo() #bar()
Because of scoping problems, attributes within a function have a lifecycle, only during the execution of the function.
Considering this code again, only if foo() is called, print() and bar() inside can survive.
def foo(): print("in foo()") def bar(): print("in bar()") return bar #Returns the body of the bar function as a return value var = foo() #At this point var is equivalent to bar var() #Executing var() is equivalent to executing bar() #Result in foo() in bar() ------------------------------------------------------- # As mentioned earlier, the reference of internal functions to the scope variables of external functions def foo(): a = 66 print("in foo()") def bar(num): print("in bar()") print(a + num) return bar var = foo() #At this point, VaR is var. var(22) #Equivalent to direct execution of bar(20) print(a) #Result in foo() Traceback (most recent call last): in bar() 88 print(a) #Departing from the body of the function, A is a local variable, reporting errors NameError: name 'a' is not defined
When the bar() function can be operated continuously
li = [1, 2, 3, 4, 5] def foo(obj): print("foo:", obj) def bar(): obj[0] += 1 print("bar:", obj) return bar var = foo(li) var() var() #Result foo: [1, 2, 3, 4, 5] #Execute foo(li) directly and return bar to var bar: [2, 2, 3, 4, 5] #For the first operation, obj[0]=1+1=2 bar: [3, 2, 3, 4, 5] #The second operation, obj[0]=2+1=3
Decorator
Introduce
Sometimes it is necessary to extend the function without affecting the original function.
Example
Need to calculate the running time of each program
import time def counts(): s=0 for i in range(100001): s+=i print('sum:%d'%s) start =time.time() counts() end=time.time() print('execution time:',(end-start)) sum:5000050000 //execution time: 0.008973836898803711
Successful implementation time calculation, but if there are thousands of functions, how to write each function is very troublesome.
The amount of code will also increase a lot from scratch.
def use_time(func): start = time.time() func() end = time.time() print('execution time:',(end-start))
After modification, a function is defined to realize the function of time calculation, which simplifies the previous operation, but when used, it is still necessary to pass the function into the function of time calculation.
def count_time(func): def wrapper(): start=time.time() func() end=time.time() print('execution time:', (end - start)) return wrapper a=count_time(counts) a()
With closures, when used, the counts function is redirected to the function reference returned by the count_time function. In this way, the counts function is used in the same way as before.
import time def count_time(func): def wrapper(): start=time.time() func() end=time.time() print('execution time:', (end - start)) return wrapper @count_time def counts(): s=0 for i in range(1000001): s+=i print ('sum:%d'%s) counts() sum:500000500000 //execution time: 0.08475852012634277
Using the decorator, when counts is called again, count_time is called and returned to it
When used, the counts function is redirected to the function call returned by the count_time function. Only counts are used in the same way as before.
Realization is to adopt decorative devices
Several Forms of Decorator
1. No parameter, no return value
def setFunc(func): def wrapper(): print('start') func() print('end') return wrapper @setFunc def show (): print('in show') show() ##Result: start in show end
2. No parameter with return value
def setFunc(func): def wrapper(): print('start') func() #At this point func() is not received by any other and is released directly. If return ed here, the end below will not print. print('end') return func()#Return func(), the above func() is useless and can be omitted directly. return wrapper @setFunc def show (): return 'in show' print(show()) start end in show #None if there is no return func
3. There are parameters and return values
def setFunc(func): def wrapper(s): print('start') func(s) print('end') return func('jc') #Execute func(jc) and return None return wrapper @setFunc def show (s): print('hello %s'%s) show('Bob') #Result start hello Bob end hello jc
4. There are parameters and return values
def setFunc(func): def wrapper(a,b): print('start') print('end') return func(a,b) return wrapper @setFunc def add(x,y): return x+y print(add(5,6)) #Result start end 11
5.Universal Decorator
According to the different definitions of the decorated function, four forms are distinguished.
Define Universal Decorator to satisfy any form of function definition
def setFunc(func): def wrapper(*args,**kwargs): #Variable parameters, receiving different parameter types print('wrapper context.') return func(*args,**kwargs) return wrapper @setFunc def func(name,age,job='student'): print(name,age,job) func('bob',17) @setFunc def stp(a,b,*c,**d): print(a,b) print(c) print(d) stp('cy','clg',1991,11,11,tk='ul') ##Result: wrapper context. bob 17 student wrapper context. cy clg (1991, 11, 11) {'tk': 'ul'}
Functions are decorated with multiple decorators
When a function is used, it may not meet expectations by extending it through a decorator.
A function is decorated with multiple decorators.
def setFunc1(func): def wrapper1(*args,**kwargs): print('Wrapper Context 1 start.'.center(42,'-')) func(*args,**kwargs) print('Wrapper Context 1 end.'.center(42,'-')) return wrapper1 def setFunc2 (func): def wrapper2(*args, **kwargs): print('Wrapper Context 2 start.'.center(42, '-')) func(*args, **kwargs) print('Wrapper Context 2 end.'.center(42, '-')) return wrapper2 @setFunc2 #F @setFunc1 #g def show(*args,**kwargs): #f print('show R.'.center(42)) show() #F(g(f)) #Result: ---------Wrapper Context 2 start.--------- ---------Wrapper Context 1 start.--------- show R. ----------Wrapper Context 1 end.---------- ----------Wrapper Context 2 end.----------
-
Procedure statement run order: bottom-up modification. First decorate with F1, then take the result as a whole, then decorate with F2.
-
Function calls: from the inside out. Similar to composite function
summary
The advantage of this implementation is that the closure function is defined. Just add @func to the function you want to decorate through the @func decorator grammar.
Users don't need to know that they are decorated when they use it. You just need to know what the original function is.
This form of function expansion, which does not change the original function, is called decorator.
When @func is executed, the original function is actually passed into the closure, and the reference to the original function points to the reference to the decorated inner function returned by the closure.
Review and summary
- Functions can be passed as parameters or return values of functions, just like ordinary variables.
- The interior of a function can define another function. Aim To realize the function of hidden function.
- Closure is also a defining form of function
- The rules of closure definition, then the external function defines an internal function. The internal function uses the variables of the external function and returns the reference of the internal function.
- In python, decorators are implemented through closures
- The function of decorator is to add function to function without changing original function.
- The use of decorators to decorate existing functions in the form of @decorator function names and add functions
- Decorators can be divided into four categories according to their parameters and return values. Universal Decorators are implemented by variable parameters (* args,**kwargs).
- A decorator can provide decorative functions for multiple functions, and a function can also use multiple decorators.
- Decorators can be implemented by classes: rewriting _init_ and _call_ functions
- Class Decorator After Decorative Function, the original reference is no longer a function, but the object of Decorator.