2. Starting from a function
2.1. Define a function
A summation function is defined as follows:
Copy the Code code as follows:
def add (x, y):
return x + y
Syntax details about parameters and return values can refer to other documents, which is skipped.
You can use lambda to define simple single-line anonymous functions. The syntax for Lambda is:
Copy the Code code as follows:
Lambda args:expression
The syntax of the parameter (args) is the same as the normal function, while the value of the expression is the return value of the anonymous function call, and the lambda expression returns the anonymous function. If we give the anonymous function a name, it looks like this:
Copy CodeThe code is as follows:
Lambda_add = lambda x, y:x + y
This is exactly the same as the SUM function defined with Def, which can be called using Lambda_add as the function name. However, the purpose of providing a lambda is to write an occasional, simple and predictable anonymous function that will not be modified. This style, although it looks cool, is not a good idea, especially when you need to expand it one day, and then you can't finish it with an expression. If you need to name a function at the beginning, you should always use the DEF keyword.
2.2. Assigning values using functions
As a matter of fact, you've already seen it, and in the previous section we assigned the lambda expression to add. Similarly, a function defined with DEF can be assigned a value, equivalent to an alias for the function, and the function can be called using this alias:
Copy the Code code as follows:
Add_a_number_to_another_one_by_using_plus_operator = Add
Print Add_a_number_to_another_one_by_using_plus_operator (1, 2)
Since functions can be referenced by variables, it is common practice to use functions as parameters and return values.
2.3. Closures
Closures are a special kind of function. If a function is defined in the scope of another function, and the function references a local variable of the external function, then the function is a closure. The following code defines a closure:
Copy the Code code as follows:
def f ():
n = 1
def inner ():
Print n
Inner ()
n = ' x '
Inner ()
The function inner is defined in the scope of F, and the local variable n in f is used in inner, which makes up a closure. The closure binds external variables, so the result of calling function f is to print 1 and ' X '. This is similar to normal module functions and the relationship of global variables defined in the module: Modifying an external variable can affect values in the inner scope, while defining the same name variable in the inner scope will obscure (hide) the external variable.
If you need to modify a global variable in a function, you can use the keyword global to decorate the variable name. There is no keyword in Python 2.x to provide support for modifying external variables in closures, and in 3.x, the keyword nonlocal can do this:
Copy the Code code as follows:
#Python 3.x supports ' nonlocal '
def f ():
n = 1
def inner ():
nonlocal n
n = ' x '
Print (n)
Inner ()
Print (n)
The result of calling this function is to print 1 and ' x ', if you have a Python 3.x interpreter, you can try to run it.
Because of the use of variables defined in the function's body, it seems that closures seem to violate the rules of the functional style without relying on external states. However, since closures are bound to local variables of external functions, and once left outside the scope of the function, these local variables will no longer be accessible from the outside, and the closure has an important feature, each execution to the closure of the definition of a new closure will be constructed, This feature makes the old closure-bound variable not change with the second call to the external function. So closures are not actually affected by the external state, and are fully compliant with functional style requirements. (There is a special case in Python 3.x, if two closures are defined in the same scope, they can interact with each other because the external variables can be modified.) )
Although closures can only play its true power as a parameter and a return value, the support for closures still boosts productivity.
2.4. As a parameter
If you are familiar with the template method pattern of OOP, you can quickly learn how to pass functions as parameters. The two are broadly consistent, but here we pass the function itself rather than the object that implements an interface.
Let's start with the SUM function defined in the previous add hot-warm:
Copy the Code code as follows:
Print add (' Triangular tree ', ' Arctic ')
Unlike the addition operator, you must be surprised that the answer is ' trigonometric functions '. This is a built-in egg ... bazinga!
Anyway Our customers have a list from 0 to 4:
Copy the Code code as follows:
LST = range (5) #[0, 1, 2, 3, 4]
Although we gave him an adder in the last section, he is still distressed by how to calculate the sum of all the elements in this list. Of course, it's a very easy task for us:
Copy CodeThe code is as follows:
Amount = 0
For num in LST:
Amount = Add (amount, num)
This is a typical instruction style code, a little bit of the problem is not, certainly can get the correct result. Now, let's try refactoring in a functional style.
The first thing you can foresee is that the sum of this action is very common, and if we abstract this action into a single function and later need to sum the other list, we don't have to write it again:
Copy the Code code as follows:
def sum_ (LST):
Amount = 0
For num in LST:
Amount = Add (amount, num)
return amount
Print Sum_ (LST)
can still continue. The SUM_ function defines such a process:
1. Use the initial value to add the first element of the list;
2. Add the next element of the list with the result of the last addition;
3. Repeat the second step until there are no more elements in the list;
4. Returns the result of the last addition.
If the product is now required, we can write a similar process-just add the sum to multiply it:
Copy the Code code as follows:
def multiply (LST):
Product = 1
For num in LST:
Product = product * num
Return product
Except for the initial value of 1 and the function add is replaced by the multiplication operator, all the other code is redundant. Why don't we abstract the process, and add, multiply, or other functions as parameters?
Copy the Code code as follows:
Def reduce_ (function, LST, initial):
result = Initial
For num in LST:
result = function (result, num)
return result
Print Reduce_ (add, LST, 0)
Now, to calculate the Chuyang product, you can do this:
Copy CodeThe code is as follows:
Print Reduce_ (lambda x, y:x * y, LST, 1)
So, what do you do if you want to use Reduce_ to find the largest value in the list? Please think for yourself:)
While there are design patterns such as template methods, the complexity often makes people more likely to write loops around. The function as a parameter completely avoids the complexity of the template method.
Python has a built-in function, reduce, which fully implements and expands the functionality of the Reduce_. The section later in this article contains an introduction to useful built-in functions. Note that our goal is to have no loops, and the use of function substitution loops is the most obvious feature of functional styles that differ from the instruction style.
* A functional language built on a class C language like Python, because the language itself provides the ability to write cyclic code, although built-in functions provide an interface for functional programming, but are generally implemented internally or using loops. Similarly, if you find that the built-in function does not meet your loop requirements, you can also encapsulate it and provide an interface.
2.5. As the return value
Returning a function typically requires a closure to work with (that is, to return a closure). Let's look at the definition of a function first:
Copy the Code code as follows:
Def map_ (function, LST):
result = []
For item in LST:
Result.append (function (item))
return result
The function Map_ encapsulates one of the most common iterations: calling a function on each element of the list. MAP_ requires a function parameter and saves the results of each call back in a list. This is an instruction-like approach, and when you know the list comprehension, there is a better implementation.
Here we skip over MAP_ 's crappy implementations and focus only on its functionality. For LST in the previous section, you may find that the final product result is always 0, because LST contains 0. To make the results look big enough, let's use MAP_ to add 1 to each element in the LST:
Copy the Code code as follows:
LST = Map_ (lambda x:add (1, x), LST)
Print Reduce_ (lambda x, y:x * y, LST, 1)
The answer is 120, which is far from being big enough. Again:
Copy CodeThe code is as follows:
LST = Map_ (Lambda x:add (ten, X), LST)
Print Reduce_ (lambda x, y:x * y, LST, 1)
Embarrassed, I really did not think the answer would be 360360, I swear not to collect Zhou 祎 any benefits.
Now look back at the two lambda expressions we wrote: The similarity is more than 90%, you can definitely use plagiarism to describe it. And the problem is not plagiarism, is to write a lot of characters have wood? If there is a function, depending on the left operand you specify, you can generate an addition function that is used like this:
Copy the Code code as follows:
LST = MAP_ (add_to (), LST) #add_to (10) Returns a function that takes a parameter and adds 10 to return
It should be much more comfortable to write. The following is the implementation of the function add_to:
Copy the Code code as follows:
def add_to (n):
return Lambda X:add (n, x)
By specifying a number of parameters for a function that already exists, a new function is generated, which only needs to pass in the remaining unspecified parameters to achieve the full functionality of the original function, which is called the partial function. Python's built-in functools module provides a function partial that can generate a partial function for any function:
Copy the Code code as follows:
Functools.partial (func[, *args][, **keywords])
You need to specify the function to generate the partial function, and specify a number of arguments or named arguments, and then partial returns the partial function, but strictly speaking, the partial return is not a function, but rather an object that can be called directly like a function, which, of course, does not affect its functionality.
Another special example is the adorner. Adorners are used to enhance or even simply change the function of the original function, I have written a document about the adorner, address here: http://www.jb51.net/article/59867.htm.
* Aside from this feature in the example, in some other functional languages, such as Scala, you can use techniques called currying to achieve more elegance. Curry is the technique of transforming a function that accepts multiple parameters into a function that takes a single parameter (the first parameter of the original function) and returns a new function that takes the remaining parameters and returns the result. As shown in the pseudo code below:
Copy the Code code as follows:
#不是真实的代码
def add (x) (y): #柯里化
return x + y
LST = MAP_ (Add (), LST)
By making the Add function curry, the add accepts the first parameter x and returns a function that takes the second parameter y, calling the function exactly the same as the previous add_to (return x + y), and no longer needs to define add_to. Does it look more refreshing? Unfortunately, Python does not support curry.
2.6. Part of the built-in function introduction
Reduce (function, iterable[, initializer])
The main function of this function is the same as the reduce_ we define. Two points to add:
Its second parameter can be any object that can be iterated (the object that implements the __iter__ () method);
If you do not specify a third argument, the first call to function uses the top two elements of iterable as parameters.
The combination of reduce and some common functions is the built-in function listed below:
Copy the Code code as follows:
All (iterable) = = reduce (lambda x, Y:bool (x and Y), iterable)
Any (iterable) = = reduce (lambda x, Y:bool (x or y), iterable)
Max (iterable[, args ...] [, Key]) = = Reduce (lambda x, y:x if key (x) > key (y) Else y, Iterable_and_args)
Min (iterable[, args ...] [, Key]) = = Reduce (lambda x, y:x if key (x) < key (y) Else y, Iterable_and_args)
Sum (iterable[, start]) = = reduce (lambda x, y:x + y, iterable, start)
Map (function, iterable, ...)
The main function of this function is the same as the map_ we define. One thing to add:
Map can also accept more than one iterable as a parameter, in the nth call function, will use Iterable1[n], iterable2[n], ... As a parameter.
Filter (function, iterable)
The function is to filter out all elements in iterable that return TRUE or bool (return value) to True when the element itself is called as a parameter and return as a list, the same as the My_filter function in the first series.
Zip (Iterable1, iterable2, ...)
This function returns a list of each element that is a tuple containing (iterable1[n], iterable2[n], ...).
Example: Zip ([1, 2], [3, 4])--[(1, 3), (2, 4)]
If the length of the argument is inconsistent, it will end at the end of the shortest sequence, and an empty list will be returned if no arguments are supplied.
In addition, you can create commonly used partial functions for these built-in functions using the functools.partial () mentioned in section 2.5 of this article.
In addition, there is a module called functional on PyPI, which provides additional interesting functions in addition to these built-in functions. However, due to the use of a few occasions, and the need for additional installation, this is not covered in this article. But I still recommend that you download this module of the pure Python implementation of the source code to see, open mind. The functions inside are very short, the source files are only 300 lines in total, the address is here: http://pypi.python.org/pypi/functional
End of this article:)