In the previous article we talked about Python's function as a return value and closure concept, we continue to explain the function to do parameters and adorners, this function is very convenient and practical, can greatly simplify the code, let's go on it!
Functions that can accept functions as arguments are called higher-order functions, such as filter, map, and reduce.
You can define a function as a higher-order function such as:
def func (x, Y, f):
return f (x) +f (y)
You can call the Func (2,-1,abs) function to return a result of 3
There are times when we don't need to explicitly define an incoming function, and it's easier to pass in an anonymous function directly.
In Python, support is provided for anonymous functions. As an example of the map () function, when you calculate f (x) =x2, you can pass in the anonymous function directly, in addition to defining an F (x) function:
1 >>> Map (Lambda x:x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]) 2 [1, 4, 9, 16, 25, 36, 49, 64, 81]
The comparison shows that the anonymous function lambda x:x * x is actually:
def f (x):
return x * x
The keyword lambda represents an anonymous function, and the x preceding the colon represents the function parameter.
There is a limit to the anonymous function, that is, there can be only one expression, no return, and the return value is the result of the expression.
With anonymous functions, you can create a function object directly without having to define the function name, and many times you can simplify the code:
1 >>> sorted ([1, 3, 9, 5, 0], lambda x, y:-cmp (x, y)) 2 [9, 5, 3, 1, 0]
When returning a function, you can also return an anonymous function:
1 >>> myabs = lambda x: x if x < 0 else x2 >>> myabs ( -1) 3 >>> myabs (1) 5 1
Sometimes we define a function that wants to dynamically add functionality at run time without changing the code of the function itself, which can be implemented with higher-order functions: You can receive a function to wrap it as a parameter, return the function:
1 def f1 (x): 2 return x*2 3 4 def new_fn (f): 5 def fn (x): # define an inner layer function 6 print "Call:" + f.__name __ + "()" 7 return F (x) # Call the function passed in in the inner layer function 8 9 return fn # returns the inner layer function G1 = NEW_FN (F1)
Execute the above code, output
CALL:F1 ()
4
We can see a F1 packaging, in its original calculation x*2 function and output its own function name. The inner function that we define in the whole process FN is the key, it is used internally by the NEW_FN passed in the parameter F, this is not the previous closure? FN calls the original F after adding additional functionality.
We can even do that.
1 f1 = NEW_FN (F1) 2 print F1 (2)
The above code outputs the same result, but passes F1 in and gets a F1, the same calling method but the new feature is higher than the previous one.
The F1 = NEW_FN (F1) in the code above is a bit too lame to use, and we can take advantage of the elegant implementation of the adorner syntax provided by Python. The definition of NEW_FN above does not change, we just need to redefine F1 on it, as follows:
1 @new_fn 2 def F1 (x): 3 return x*2 4 5 @new_fn 6 def f2 (x): 7 return X/2 8 9 Print F1 (2) p Rint F2 (2)
The output is as follows:
CALL:F1 ()
4
CALL:F2 ()
1
We add a @new_fn in front of the function to represent the F1 this function to decorate processing, call the F1 after the direct call of the processing of F1, for the F2 is also so, use up everything is very convenient.
Note that the above code can only be F1 such a single parameter function can be decorated, if the need to decorate two parameters of the function that NEW_FN can not be achieved, in fact, it is very simple, we only need to use *args, **kw, can ensure that any number of parameters can always be called normally, as follows.
1 def new_fn (f): 2 def fn (*args, **kw): # can pass in any parameter 3 print ' call ' + f.__name__ + ' () ... ' 4 return F (*args, **kw) 5 return fn 6 7 @new_fn 8 def add (x, y): 9 return x + y print Add (1, 2)
In fact, careful observation we found that although the call to add passed the parameter 1, 2, but it is only passed to the adorner, which is the FN above, we can change its parameters in the adorner at any time and then passed to F.
It is now possible to implement the function correctly after the above steps. But what if we come up with demand again (programmers are always afraid of this??) )
For the above @new_fn adorner:
1 def new_fn (f): 2 def fn (*args, **kw): 3 print ' call ' + f.__name__ + ' () ... ' 4 return F (*args, **kw) 5 RETURN fn
found that for the decorated function, the NEW_FN printed statement is immutable (except for the name of the function).
If the function is very important, want to print out ' [info] call XXX (), some functions are not very important, want to print out ' [debug] calls xxx () ... ', at this time, the NEW_FN function itself needs to pass the "info" or "debug" parameters such as , similar to this:
1 @new_fn (' DEBUG ') 2 def my_func (): 3 Pass
The call to translate the above definition into a higher-order function is:
1 My_func = NEW_FN (' DEBUG ') (My_func)
The above statement looks more like a detour, and then expands:
1 newfn_decorator = NEW_FN (' DEBUG ') 2 My_func = Newfn_decorator (My_func)
The above statement is also equivalent to:
1 log_decorator = NEW_FN (' DEBUG ') 2 @log_decorator3 def my_func (): 4 Pass
So, the NEW_FN function with parameters first returns a decorator function, and then lets the decorator function receive My_func and return the new function:
1 def new_fn (prefix): 2 def newfn_decorator (f): 3 def wrapper (*args, **kw): 4 print ' [%s]%s () ... '% (prefix, F.__NAME__) 5 return F (*args, **kw) 6 return wrapper 7 return newfn_decorator 8 9 @new_fn (' DEBUG ') Ten Def Test (): one pass12 print test ()
The results of the implementation are as follows:
[DEBUG] Test () ...
None
For this 3-layer nested decorator definition, you can first take it apart:
1 # Standard Decorator:2 def newfn_decorator (f): 3 def wrapper (*args, **kw): 4 print ' [%s]%s () ... '% (prefix, f.__name_ _) 5 return F (*args, **kw) 6 return wrapper 7 return Newfn_decorator 8 9 # back Decorator:10 def new_fn (prefix): 1 1 return Newfn_decorator (f)
When you open it, the call will fail because in the 3-layer nested decorator definition, the outermost wrapper reference prefix, so it is difficult to break a closure into a normal function call. Programming languages that do not support closures require more code to implement the same functionality.
Using adorners we can greatly simplify code, avoid writing repetitive code for each function, implement print logs (@log), detect performance (@perfirmance), Database transactions (@transaction), URL routing ('/register ') ), and using an adorner with parameters, we can do some processing, pretreatment and so on.
Easy to understand closures and adorners in Python (bottom)