3.23
Recalling the previous section
*args,**kwargs
-
* Args: * for the extra arguments in a position assigned to the args argument
-
** kwargs, ** the extra keyword arguments dictionary assigned to become kwargs
-
In arguments , * a break
-
def index(*args,**kwargs): print(x,y) def wrapper(*args,**kwargs): # (1,2,34),{'x':1,'y':2} index(*args,**kwargs) # index(1,2,34,x=1,y=2) wrapper(1,2,34,x=1,y=2)
In this format, the format of the arguments to pass intact call wrapper index
Namespace and scope
- The function nested relation namespace definition of phase, i.e. to determine when the detected grammar
- Function object
- It can function as the argument to another function
- It can be used as function return values
Nested function definition
-
A function in the function package
def outter(): def inner(): pass return inner # 不加括号,返回 inner的内存地址
Closure function
-
Built-in functions, and cited its outer function name
def f1(): x = 1 y = 2 z = 3 f1()
f1 namespace normal after the call is finished cleaning up, but if one's name is a reference to the other places, and that his reference count there, his name space will not be recovered
Parameter passing mode
-
Formal parameter values as a function of pass
-
By way of closure body mass as a function of the value
def outter(x): def wrapper(): print(x) return wrapper # 处于局部 wrapper = outter(1) # 处于全局
-
Namespace: different namespaces can use the same name, so the local to the global function assignment of the same name function is possible
Regular course
Decorator
what is
-
Refers to a tool device, you may be defined as a function
-
Decorative refers to add functionality to other tools
-
Decorator:
The definition of a tool (class, function, currently only learn function), used to add functionality to another function
Why do you use
In a real development environment for the expansion of the original function, should follow the Open Closed Principle , the software can not be easily modified to run online or off
Open closed: Want to add new functionality to a function, but do not want to change the source code for this function
- Open: open to expand functionality
- Closed: to modify the source code is closed
Add new features to the original function, it may involve a number of places, if a mistake, the whole program error, led to launch a body.
Decorator is not modified by decorative objects and calls the source code under the premise, to add functionality to the original function
How to use
Examples
def index(x,y):
print('index %s %s'%(x,y))
index(111,222)
There is a normal function, this function would now like to add a new function, a function of run time statistics
Method a: modifying the source code
-
With a time module
time.time
returns the current timestamp: From 1970 to the current time in seconds -
Run functions before time.time, after the end of the run time.time, end time function decreasing function of the starting time is a function of execution time
import time def index(x,y): start = time.time() time.sleep(1) print('index %s %s'%(x,y)) end = time.time() print(end - start) index(111,222)
Does implement the function, there is no way to modify the function call, but modify the source code, do not meet the Open Closed Principle
Method two: before and after the call statement added
-
Before and after the call with time.time
import time def index(x,y): time.sleep(1) print('index %s %s'%(x,y)) start = time.time() index(111, 222) end = time.time() print(end - start)
When a need to count every time, before and after calls to add this few lines of code to achieve without changing the source code, without changing the way calls, but in many places need this new feature, you need to repeat this to write a few words statement, the code is redundant, inappropriate
Solution: decorator
-
Use function closures to solve the problem of code redundancy, but is called to become wrapper (), and the index is written 111,222 dead
import time def index(x,y): time.sleep(1) print('index %s %s'%(x,y)) def wrapper(x,y): start = time.time() index(111, 222) end = time.time() print(end - start) wrapper()
-
Improved 1, do not write the wrapper dead:
index(x,y) ... wrapper(111,222)
-
Improved 2, **, you can pass multiple parameters, write parameters alive :
def index(x,y,z): ... def wrapper(*args,**kwargs): ... index(*args,**kwargs) wrapper(111,222,33,444)
-
Improved 3: Prefer index only a decorative function, all functions can be decorated wrapper wanted: a need to pass into the wrapper function as a parameter, but the parameter can not be passed in this function: the use of the closure function to the function as an argument, the function to write live
def outter(func): # 把要装饰的函数当作参数传给装饰器的包 def wrapper(*args,**kwargs): func(*args,**kwargs) return wrapper def index(x,y): print(x,y) f = outter(index) # 实际上是运行了wrapper,wrapper中的func实际上是调用时当作参数传入的函数 f(1,2)
Solved without changing the source code, write dead issue, but also changed the way calls
-
Final: do not change the way calls
Named improved function with the name of the original function of perpetrating a fraud
index = outter(index) index(1,2)
Method summary
-
The decorative features made closure function
-
Decorated in the package to function as a parameter passed nested functions
-
Closure function is decorated with the package for the object function, the original function of the received parameters
-
Package function returns a function of the nested function thereof
-
Renamed, perpetrating a fraud
index = outter(index) index()
To achieve the final effect: the real ones
This approach has the original function returns a value at the time the problem: The original function has been replaced with a wrapper function, call the index is in fact calling wrapper, while the wrapper does not return a value, it is necessary to allow the return of the original wrapper function's return value
Ultimately improving
In the decorator, the return value returned by the original function should have
def outter(func): # 把要装饰的函数当作参数传给装饰器的包
def wrapper(*args,**kwargs):
func(*args,**kwargs)
res = func(*args,**kwargs)
return res # wrapper函数原函数的运行结果
return wrapper # 包函数在偷梁换柱的时候返回内嵌函数的函数体
def index(x,y):
print(x,y)
index = outter(index)
index(1,2)
Finally reached, call the same way, the same source code, the return value is the same, to achieve the real ones
Syntactic sugar @ decorator name
Every decorative function to be perpetrating a fraud on the original function name
-
index = outter(index) index(1,2)
There are statements on this simple syntax: Write on a separate line is directly above the decorative objects @装饰器名字
, python automatically give you perpetrating a fraud
-
def timmer(): # 装饰器必须在被装饰函数的上面 ... @timmer # 相当于帮你做了 index = timmer(index) def index(): ...
-
Decorator needs to be placed on top of the decorator , or to run @ this line of code, decorator has not yet been defined, an error
-
A function may be superimposed plurality of decorator
Load order:
@deco1 # deco1.wrapper的内存地址 = deco1(index) @deco2 # deco2.wrapper的内存地址 = deco2(index) @deco3 # deco3.wrapper的内存地址 = deco3(index) def index(): ...
to sum up
The basic template
def outter(func):
def wrapper(*args,**kwargs):
res = func()
# 新功能
...
return res
return wrapper
@outter
def index(x,y):
# 原功能
...
index(x,y)
This is getting a template, the original function writes index, new features written wrapper, you get a complete no-argument decorator