Many languages allow functions to be passed as parameters to other parameters: so-called higher-order functions. There are similar features in python:
一、map/reduce、filter、sorted
def fn_map(x): print("fn_map->", x) return 10 * x L = [3, 4, 6, 8] print(list(map(fn_map, L))) print("\n")
output:
fn_map-> 3 fn_map-> 4 fn_map-> 6 fn_map-> 8 [30, 40, 60, 80]
Combined with map, we add the reduce function (final effect: square all elements * 10, and finally get the "square root" of the "sum of squares")
def fn_sqrt(x, y): print("fn_sqrt->", x, ",", y) return math.sqrt(x ** 2 + y ** 2) def fn_map(x): print("fn_map->", x) return 10 * x L = [3, 4, 6, 8] result = reduce(fn_sqrt, map(fn_map, L)) print(result) print("\n") print(math.sqrt((3 * 10) ** 2 + (4 * 10) ** 2 + (6 * 10) ** 2 + (8 * 10) ** 2))
Note: To import math first, the output of the above code is as follows:
fn_map-> 3 fn_map-> 4 fn_sqrt-> 30 , 40 fn_map-> 6 fn_sqrt-> 50.0 , 60 fn_map-> 8 fn_sqrt-> 78.10249675906654 , 80 111.80339887498948 111.80339887498948
The above example may not be very practical. Let's give a more practical example, capitalize the first letter of each word, and lowercase other letters.
def normalize(name): return name[:1].upper() + name[1:].lower() L1 = ['adam', 'LISA', 'barT'] print(list(map(normalize, L1)))
output:
1.2 filter
The filter is similar to the stream filter in java8, which can filter the elements in the collection according to certain rules.
Example 1: Find even numbers within 10
result = filter(lambda x: x % 2 == 0, range(1, 11)) print(list(result)) # The above writing is equivalent to the following def even(x): return x % 2 == 0 print(list(filter(even, range(1, 11))))
output:
[2, 4, 6, 8, 10] [2, 4, 6, 8, 10]
Example 2: Find the "number of times" within 200 (ie: from left to right, from right to left, all are the same number, such as: 131, 141)
def is_palindrome1(n): if n < 10: return True s = str(n) for i in range(0, int(len(s) / 2)): if s[i] == s[-i - 1]: return True return False def is_palindrome2(n): s1 = str(n) s2 = list(reversed(s1)) return list(s1) == s2 print(list(filter(is_palindrome1, range(1, 201)))) print(list(filter(is_palindrome2, range(1, 201))))
output:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191] [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191]
1.3 sorted
The built-in sorting function sorted in python supports the sorting of numbers/letters/ and complex objects. The default is to sort from small to large. The sorting rules for complex objects can be customized by developers. Refer to the example below:
origin = [-1, 3, -5, 2, -4, 6] # Sort from smallest to largest a = sorted(origin) print(a) # Sort by absolute value of abs, from small to large a = sorted(origin, key=abs) print(a) # Sort from largest to smallest a = sorted(origin, reverse=True) print(a) origin = ["Xy", "Aa", "Bb", "dd", "cC", "aA", "Zo"] # Sort alphabetically by ascii value from smallest to largest print(sorted(origin)) # Sort the values after converting the letters to uppercase (ie: ignore case) print(sorted(origin, key=str.upper)) # Reverse sort the values after capitalizing the letters print(sorted(origin, key=str.upper, reverse=True)) # complex object sorting origin = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)] def by_name(t): return t[0] # Sort by name print(sorted(origin, key=by_name)) def by_score(t): return t[1] # Sort by score print(sorted(origin, key=by_score, reverse=True))
output:
[-5, -4, -1, 2, 3, 6] [-1, 2, 3, -4, -5, 6] [6, 3, 2, -1, -4, -5] ['Aa', 'Bb', 'Xy', 'Zo', 'aA', 'cC', 'dd'] ['Aa', 'aA', 'Bb', 'cC', 'dd', 'Xy', 'Zo'] ['Zo', 'Xy', 'dd', 'cC', 'Bb', 'Aa', 'aA'] [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)] [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]
2. Delayed computation/closure
Python's function definitions can be nested (ie: functions are defined inside functions), and it is easy to implement delayed computation using this feature :
import time def export1(month): print("export1 month:", month, " doing...") time.sleep(5) print("export1 done!") def export2(month): def do(): print("export2 month:", month, " doing...") time.sleep(5) print("export2 done!") return do export1(10) print("----------------") r2 = export2(10) print(r2) r2 ()
Here we simulate a time-consuming export function (assume: the month is required to be passed in, and then the report data of that month is exported), export1 is the regular version, and the call to export1 will be executed immediately. And export2 returns an internal function do(). After calling export2, it returns a Function, which is not actually executed (it can be understood as: what is returned is the business processing algorithm, not the processing result). When the result is really needed, Then call the "return function".
The output of the above code is as follows:
export1 month: 10 doing... export1 done! ---------------- <function export2.<locals>.do at 0x107a24a60> export2 month: 10 doing... export2 done!
Closure
Many languages support the closure feature. Of course, this is indispensable in python. Refer to the following example:
def my_sqrt1(n): r = [] def do(): for i in range(1, n + 1): r.append(i ** 2) return r return do a = my_sqrt1(4) print(type(a)) b = a() print(type(b)) print(b)
output:
<class 'function'> <class 'list'> [1, 4, 9, 16]
Closures have a classic pitfall: don't use "variables whose value changes" (eg: variables in for loops) in closure functions . The reason is: the closure in python is essentially an "internal function" delayed calculation. If there is a loop variable, the closure function will not be executed during the loop. When the loop is over, the loop variable referenced in the closure is actually The final value after the loop ends. It's a bit of a twist, but here's an example:
def my_sqrt2(n): r = [] for i in range(1, n + 1): def do(): r.append(i ** 2) return r return do a = my_sqrt2(4) print(type(a)) b = a() print(type(b)) print(b)
output:
<class 'function'> <class 'list'> [16]
Explain: when calling a = my_sqrt2(4), my_sqrt2(4) will be executed immediately. At this time, the fox loop inside will be executed. Finally, the value of i will stop at 4, and then this value will be enclosed in the do function, and will not be executed immediately. implement. Then when a() is called again, the do() function is actually called at this time. At this time, the i value = 4, so in the final r[] list, only one value 4*4=16 is recovered.
If you have to use the loop variable, you can only try to enclose the loop variable in an internal function, and then use it again, such as the following:
def my_sqrt3(n): def f(j): def g(): return j ** 2 return g r = [] for i in range(1, n + 1): r.append(f(i)) return r a = my_sqrt3(4) print(type(a)) for x in a: print(x())
It is interesting to study this example carefully, r.append(f(i)), what is appended to the list is not the calculation result, but the function g returned in f(j), so a = my_sqrt3(4) Here, a gets is a list composed of functions, and then each instance of the g function in the list closes the variable i of the current loop. Because of the closure, the value of i has been sealed inside g, no matter how the external for loop variable , will not affect the function g.
The output is as follows:
<class 'list'> 1 4 9 16
Finally, let's look at a closure homework problem on Mr. Liao's tutorial, and write a counter in the way of closure:
def create_counter1(): r = [0] def counter(): r[0] += 1 return r[0] return counter count = create_counter1(); print([count(), count(), count()])
output:
[1, 2, 3]
For programmers with cleanliness, it may feel that it is a bit wasteful to set up an additional list that only saves one element. It can be written differently:
def create_counter2(): n = 0 def counter(): nonlocal n n += 1 return n return counter count = create_counter2(); print([count(), count(), count()])
output:
[1, 2, 3]
Note that there is a keyword nonlocal , which is known as a new keyword introduced by python3, in order to allow the inner function of the closure to read and write variables outside the inner function. (But in the first writing method, isn't r=[0] also defined externally? The difference is that list is a complex variable type, while in the second writing method n is a simple type variable. As a python beginner, no I understand this philosophy very well ^_~)