This article mainly introduces the Python function programming guide (1): function programming overview, this article explains what is functional programming overview, what is functional programming, why to use functional programming, how to identify functional style and other core knowledge. For more information, see
1. Functional Programming Overview
1.1. What is functional programming?
Function programming uses a series of functions to solve the problem. The function only accepts input and generates output, and does not contain any internal status that can affect the output. In any case, using the same parameter to call a function always produces the same result.
In a functional program, input data flows through a series of functions, and each function generates output based on its input. Function styles avoid writing side effects functions: modifying internal states, or other changes that cannot be reflected in the output. A function without a boundary effect is called a Pure functional function (purely functional ). Avoiding the boundary effect means that the data structure variable when the program runs is not used, and the output only depends on the input.
It can be considered that functional programming is on the opposite side of object-oriented programming. Objects usually contain internal states (fields) and many functions that can modify these States. Programs are composed of constantly changing states. Functional Programming tries to avoid state changes, data streams are transferred between functions for work. However, this does not mean that functional programming and object-oriented programming cannot be used at the same time. In fact, complex systems generally adopt object-oriented modeling, however, the combination of functional styles allows you to enjoy the advantages of functional styles.
1.2. Why functional programming?
The functional style is generally considered to have the following advantages:
1. Logic verifiable
This is an academic advantage: the absence of boundary effects makes it easier to logically prove that the program is correct (rather than passing tests ).
2. Modularization
Functional Programming advocates the simple principle. A function only does one thing and splits large functions into as small modules as possible. Small functions are easier to read and check for errors.
3. componentization
Small functions are easier to combine to form new functions.
4. Easy debugging
Refined and clearly defined functions make debugging easier. When the program is not running normally, every function is an interface that checks whether the data is correct. It can quickly exclude the code without any problems and locate the problem.
5. Easy to test
Functions independent of the system state do not need to construct a test pile before the test, making it easier to write unit tests.
6. Higher Productivity
Function programming produces less code than other technologies (usually about half of other technologies) and is easier to read and maintain.
1.3. How to identify functional styles?
Languages that support functional programming generally have the following features. Code that uses these features can be considered functional:
The function is a first-class citizen.
A function can be passed as a parameter or returned as a return value. This feature makes the template method mode very easy to write, which also promotes this mode to be used more frequently.
Take a simple set sorting as an example. Assume that lst is a number set and has a sorting method, sort needs to determine the order as a parameter.
If a function cannot be used as a parameter, the sort method of lst can only accept common objects as parameters. In this way, we need to first define an interface, then define a class that implements this interface, and finally pass an instance of this class to the sort method, which calls the compare method of this instance, like this:
The Code is as follows:
# Pseudocode
Interface Comparator {
Compare (o1, o2)
}
Lst = list (range (5 ))
Lst. sort (Comparator (){
Compare (o1, o2 ){
Return o2-o1 // Reverse Order
})
It can be seen that we define a new interface and a new type (here it is an anonymous class), and a new object is only used to call a method. What if this method can be passed directly as a parameter? It should look like this:
The Code is as follows:
Def compare (o1, o2 ):
Return o2-o1 # Reverse Order
Lst = list (range (5 ))
Lst. sort (compare)
Note that the previous Code has used anonymous skills to save a lot of code, but it is still easier to directly pass functions.
Anonymous functions (lambda)
Lambda provides the ability to quickly write simple functions. Lambda removes the need to jump to another location during encoding for occasional actions.
Lambda expressions define an anonymous function. If this function is only used in the encoding position, you can define it and use it directly:
The Code is as follows:
Lst. sort (lambda o1, o2: o1.compareTo (o2 ))
I believe that from this small example, you can also feel the powerful production efficiency :)
Built-in template functions of the encapsulation Control Structure
To avoid the boundary effect, the functional style tries its best to avoid using variables, while loop variables defined only to control the process and temporary variables generated in the process are undoubtedly the most unavoidable.
If we need to filter the number set to get all positive numbers, the script-style code should look like this:
The Code is as follows:
Lst2 = list ()
For I in range (len (lst): # simulate a classic for Loop
If lst [I]> 0:
Lst2.append (lst [I])
This code shows the entire process from creating a list, looping, taking out elements, judging, and adding to the new list. It seems like a dumb who needs hands-on guidance. However, the "filter" action is very common. why can't the interpreter master the filter process, but we only need to tell it the filter rules?
In Python, filtering is implemented by a built-in function named filter. With this function, the interpreter learns how to "filter", and we only need to tell the rule:
The Code is as follows:
Lst2 = filter (lambda n: n> 0, lst)
The benefit of this function is not only the simplicity of writing a few lines of code.
After encapsulating the control structure, you only need to describe the function in the code, instead of the practice. Such code is clearer and more readable. Because it avoids the interference of the control structure, the second code clearly makes it easier for you to understand its intention.
In addition, because the index is avoided, it is unlikely that the Code will trigger the subscript out of bounds exception unless you manually create one.
Functional Programming Languages typically encapsulate several common actions such as "filter" as template functions. The only drawback is that these functions require a small amount of learning costs, but they cannot cover up the benefits of using them.
Closure (closure)
A closure is a function bound to a variable in an external scope (but not a global variable. In most cases, external scopes refer to external functions.
The closure contains the function body and the reference of the variable name in the required external function ". Referencing a variable name means that the variable name is bound, rather than the object to which the variable actually points. If you assign a value to the variable again, the new value will be accessed in the closure.
Closures make functions more flexible and powerful. Even if the program runs to exit the external function, if the closure is still visible, the bound variable is still valid. Every time you run to the external function, the closure is re-created and the bound variables are different, there is no need to worry that the variables bound to the old closure will be overwritten by new values.
Return to the example of filtering data sets. Assume that the boundary value 0 in the filter condition is not fixed, but controlled by the user. If no closure exists, the Code must be changed:
The Code is as follows:
Class greater_than_helper:
Def _ init _ (self, minval ):
Self. minval = minval
Def is_greater_than (self, val ):
Return val> self. minval
Def my_filter (lst, minval ):
Helper = greater_than_helper (minval)
Return filter (helper. is_greater_than, lst)
Please note that we have now compiled a function my_filter for the filter function. As you can see, we need to hold another operand minval elsewhere (in this example, the class greater_than_helper.
If closure is supported, because closure can directly use variables with external scopes, greater_than_helper is no longer needed:
The Code is as follows:
Def my_filter (lst, minval ):
Return filter (lambda n: n> minval, lst)
It can be seen that the closure saves a lot of code without affecting readability.
Functional Programming Languages provide different degrees of support for closures. In Python 2.x, the closure cannot modify the value of the bound variable. All changes to the bound variable are regarded as creating a local variable with the same name and hiding the bound variable. In Python 3. x, A New Keyword nonlocal is added to support variable modification. However, regardless of the degree of support, you can always access (read) bind variables.
Built-in immutable data structure
To avoid boundary effects, an unchangeable data structure is an indispensable part of functional programming. The immutable data structure ensures data consistency and greatly reduces the difficulty of troubleshooting.
For example, tuple in Python is immutable, and all operations on tuples cannot change the content of the tuples. All operations that attempt to modify the content of the tuples will generate an exception.
Function programming languages generally provide two types of data structures (variable and immutable), and they are recommended to use immutable versions.
Recursion
Recursion is another method to replace loops. Recursion is actually a common form of functional programming, which is often seen in some algorithms. But put it to the end, because we generally seldom use recursion. If a recursion cannot be optimized by the compiler or interpreter, it will easily cause stack overflow. On the other hand, complicated recursion is often confusing, and the loop is not clear, therefore, many best practices point to the use of loops rather than recursion.
This series of short articles will not focus on Recursive use.
<第一节完>