part5-2 Python 函數高級(函數變量、函數參數、函數作為返回值,lambda 表達式),函數練習



一、 函數高級內容


Python 中的函數是“一等公民”,因此函數本身也是一個對象,函數即可用於賦值,也可用作其函數的參數,還可作為其他函數的返回值

1、 使用函數變量
Python的函數也是一種值。所有函數都是 function 對象,可以把函數本身賦值給變量,就像把整數、列表、元組等賦值給變量一樣。把函數賦值給變量后,就可通過變量來調用函數。示例如下:
 1 def pow(base, exponent):  2     """計算乘方"""
 3     result = 1
 4     for i in range(1, exponent + 1):  5         result *= base  6     return result  7 my_fun = pow        # 將 pow 函數賦值給 my_fun 變量
 8 print(my_fun(3, 3))     # 計算3的3次方,輸出:27
 9 
10 def area(length, width): 11     """計算面積"""
12     return length * width 13 my_fun = area       # 將 area 函數賦值給 my_fun 變量
14 print(my_fun(4, 5))     # 計算面積,輸出:20
這里對 my_fun 變量賦值不同的函數,可以讓 my_fun 在不同的時間指向不同的函數來讓程序更加靈活。使用函數變量的好處是讓程序更加靈活。

2、 使用函數作為函數形參
在函數中定義函數形參,這樣可在調用該函數時傳入不同的函數作為參數,從而動態改變這段代碼。示例如下:
 1 def map(data, fn):  2     """定義函數類型的形參,其中 fn 是一個函數"""
 3     result = []  4     # 遍歷 data 列表中的每個元素,並用 fn 函數對每個元素進行計算
 5     # 然后將計算結果作為新數組的元素
 6     for e in data:  7  result.append(fn(e))  8     return result  9 # 定義一個計算平方的函數
10 def square(n): 11     return n * n 12 # 定義一個計算立方的函數
13 def cube(n): 14     return n * n * n 15 # 定義一個計算階乘的函數
16 def factorial(n): 17     result = 1
18     for i in range(2, n + 1): 19         result *= i 20     return result 21 data = [2, 4, 6, 8, 10] 22 print("列表原始數據:", data) 23 print("計算列表元素的平方:") 24 print(map(data, square)) 25 print("計算元素的立方:") 26 print(map(data, cube)) 27 print("計算元素的階乘:") 28 print(map(data, factorial)) 29 print(type(map)) 30 
31 運行程序輸出如下: 32 列表原始數據: [2, 4, 6, 8, 10] 33 計算列表元素的平方: 34 [4, 16, 36, 64, 100] 35 計算元素的立方: 36 [8, 64, 216, 512, 1000] 37 計算元素的階乘: 38 [2, 24, 720, 40320, 3628800] 39 <class 'function'>
這里定義的 map() 函數的第二個參數是一個函數類型參數,這意味着每次調用函數時可以動態傳入一個函數。傳入不同的函數,可以動態改變 map() 函數中的部分計算代碼。Python3 內置的 map 函數與這里定義的 map 函數功能相似,但是更強大。

3、 使用函數作為返回值
Python支持使用函數作為其他函數的返回值。示例如下:
 1 def foo(type):  2     """定義一個函數,該函數包含局部函數"""
 3     def square(n):  4         """定義一個計算平方的局部函數"""
 5         return n * n  6     def cube(n):  7         """定義一個計算立方的局部函數"""
 8         return n * n * n  9     def factorial(n): 10         """定義一個計算階乘的局部函數"""
11         result = 1
12         for i in range(2, n + 1): 13             result *= i 14         return result 15     # 調用局部函數
16     if type == 'square': 17         # 注意返回的函數不能加括號,只返回函數名稱
18         return square 19     elif type == 'cube': 20         return cube 21     else: 22         return factorial 23 # 調用 foo 函數,程序返回一個嵌套函數
24 cube = foo('cube') 25 print(cube(10))             # 計算立方,輸出:1000
26 square = foo('square') 27 print(square(5))            # 計算平方:輸出:25
28 factorial = foo('factorial') 29 print(factorial(5))         # 計算階乘:輸出:120
這次定義的 foo 函數體定義了3個局部函數,foo 函數由參數來決定返回哪一個函數。

二、 局部函數與 lambda 表達式

lambda 表達式是功能更靈活的代碼塊,可以在程序中被傳遞和調用。

從前面的局部函數內容可知,局部函數的作用域僅在其封閉函數體內,離開這個封閉函數體,局部函數的函數名就失去了意義(當然可以用返回函數名的方法進行調用),可考慮用 lambda 表達式簡化局部函數的寫法。

1、 使用 lambda 表達式代替局部函數
使用 lambda 表達式簡化前面的 foo 函數,代碼如下:
 1 def foo(type):  2     result = 1
 3     # 該函數返回的是 lambda 表達式
 4     if type == 'square':  5         return lambda n: n * n  6     elif type == 'cube':  7         return lambda n: n * n * n  8     else:  9         return lambda n: (n + 1) * n / 2
10 # 調用 foo 函數,程序返回的是一個嵌套函數
11 square = foo('square') 12 print(square(10))       # 計算平方,輸出:100
13 cube = foo('cube') 14 print(cube(10))         # 計算立方,輸出:1000
15 other = foo('other') 16 print(other(10))        # 求和,輸出:55.0
這次定義的 foo 函數體內,return 后面使用 lambda 關鍵字定義的是 lambda 表達式。Python 要求 lambda 表達只能是單行表達式,不允許使用復雜的函數形式。

lambda 表達式的語法格式如下:
lambda [參數列表]: 表達式

lambda 表達式的幾個要點:
(1)、lambda 表達式必須使用 lambda 關鍵字定義。
(2)、在 lambda 關鍵字之后、冒號左邊的是參數列表,可以不給參數,也可以給多個參數。多個參數用逗號分隔,冒號右邊是 lambda 表達的返回值。
(3)、lambda 表達式也叫做匿名函數,也是單行函數體的函數。

函數比 lambda 表達式的適應性更強,lambda 表達式只能創建簡單的函數對象(適合函數體為單行的情形)。lambda表達的兩個用途:
(1)、對於單行函數,使用 lambda 表達式更簡潔,省去定義函數的過程。
(2)、對於不需要多次復用的函數,使用 lambda 表達式可以在用完之后立即釋放,提高性能。

下面示例使用內置的 map() 函數,參數是 lambda 表達式:
1 # 計算平方
2 x = map(lambda x: x * x, range(5)) 3 print([i for i in x]) 4 # 計算偶數的平方
5 y = map(lambda x: x * x if x % 2 ==0 else 0, range(5)) 6 print([i for i in y])
這段代碼中 map 函數是內置函數,第一個參數是函數,第二個參數通常是列表、元組等。這里傳入的 lambda 表達式,是簡化的函數,這樣程序更加簡潔,性能也更好。

三、 小結

函數和lambda 表達式是 Python 編程的兩大核心機制之一。Python 支持面向過程編程,也支持面向對象編程。函數和 lambda 表達式是面向過程編程的語法基礎,需要重點掌握。

要掌握函數的定義、函數調用語法,函數位置參數與關鍵字參數的區別和用法、形參默認值等特性。此外,函數也是一個 function 對象,函數可作為其他函數的參數,也可作為其它函數的返回值。把函數當成參數傳入其他函數,可以讓編程變得更加靈活。

lambda 表達式是單行函數的簡化版本,功能比較簡單。

練習:
1、 定義一個函數,該函數可接收一個 list 作為參數,該函數使用直接選擇排序對 list 排序。
 1 def choose_sort(sequence):  2     length = len(sequence)  3     for i in range(length):  4         for j in range(i + 1, length):  5             if sequence[i] > sequence[j]:  6                 sequence[i], sequence[j] = sequence[j], sequence[i]  7 
 8 seq = [100, 31, -50, 1, 3, 28,  -11, 85]  9 choose_sort(seq) 10 print(seq)      # 輸出:[-50, -11, 1, 3, 28, 31, 85, 100]

2、定義一個函數,該函數接收一個 list 作為參數,該函數使用冒泡排序對 list 排序。
默認按升序排序,即從小到大排序。
冒泡排序思路:首先,列表每兩個相鄰的數,如果前邊的數比后邊的數大,那么交換這兩個數,第一次遍歷完后,最大的這個數就在列表的末尾,接着第二次遍歷,指針回到列表起始處,繼續比較兩個相鄰的數,如果前邊比后邊大的,就交換這兩個數,以此類推。
 1 def bubble_sort(sequence):  2     length = len(sequence)  3     for i in range(length):  4         is_sorted = True     # 如果內層循環已經是從小到大的順序,可通過判斷這個變量來結束循環
 5         for j in range(length - i - 1):     # 減 1 是避免遍歷到最后一個元素
 6             if sequence[j] > sequence[j + 1]:  7                 sequence[j], sequence[j + 1] = sequence[j + 1], sequence[j]  8                 is_sorted = False  9         if is_sorted: return        # 如果內層循環已排序完成,就結束外層循環
10 
11 seq = [100, 31, -50, 1, 3, 28,  -11, 85] 12 bubble_sort(seq) 13 print(seq)      # 輸出:[-50, -11, 1, 3, 28, 31, 85, 100]

3、定義一個 is_leap(year) 函數,判斷 year 是否為閏年。若是閏年則返回 True; 否則返回 False.
閏年分為普通閏年和世紀閏年。普通閏年是指公歷年份是4的倍數,例如2016年就是閏年。世紀閏年是指公歷年份是整百數,必須是400的倍數才是閏年,例如1900年不是世紀閏年,2000是世紀閏年。
 1 def is_year(year):  2     year = int(year)  3     # 過濾整百數年份,判斷普通閏年
 4     if (year % 4 == 0) and (year % 100 != 0):  5         return True  6     # 判斷世紀閏年
 7     elif year % 400 == 0:  8         return True  9     else: 10         return False 11 
12 while True: 13     year = input("請輸入年份:") 14     if year == 'q' or year == 'exit': 15  exit(0) 16     else: 17         print("%s是否是閏年?%s" % (year, is_year(year)))

4、 定義一個 count_str_char(my_str) 函數,該函數返回參數字符串中包含多少個數字、多少個英文字母、多少個空白字符、多少個其它字符。
 1 def count_str_char(my_str):  2     char_num, digit_num, space_num, other_num = 0, 0, 0, 0  3     for s in my_str:  4         if s.isdigit(): digit_num += 1
 5         elif s.isalpha(): char_num += 1
 6         elif s.isspace(): space_num += 1
 7         else: other_num += 1
 8     return char_num, digit_num, space_num, other_num  9 
10 while True: 11     my_str = input("請輸入一個字符串:") 12     if my_str == 'q': 13  exit() 14     char_num, digit_num, space_num, other_num = count_str_char(my_str) 15     print("字符個數是:", char_num) 16     print("數字個數是:", digit_num) 17     print("空白個數是:", space_num) 18     print("其它字符個數是:", other_num) 19     print("-" * 30)

5、定義一個函數fn1(n),該函數返回 1到n 的立方和,即求:1+2*2*2+3*3*3+...+n*n*n
 1 def fn1(n):  2     if n < 2:  3  exit()  4     result = 1
 5     for i in range(2, n + 1):  6         result += i * i * i  7     return result  8 n = int(input("請輸入一個數字:"))  9 sum = fn1(n) 10 print("1~%d的立方和是:%s" % (n, sum))

6、定義一個fn2(n) 函數,該函數返回 n 的階乘。
 1 def fn2(n):  2     if n < 2:  3         return 1
 4     result = 1
 5     for i in range(2, n + 1):  6         result *= i  7     return result  8 
 9 def fn3(n): 10     """用遞歸函數來實現階乘"""
11     if n <= 1: 12         return 1
13     else: 14         return fn3(n - 1) * n 15 
16 def fn4(n): 17     """用列表的方式計算階乘"""
18     if n <= 1: 19         return 1
20     my_list = [1] 21     for _ in range(n): 22         my_list.append(my_list[-1] * len(my_list)) 23     return my_list[-1] 24 
25 n = int(input("請輸入一個整數:")) 26 print("%d的階乘是:%d" % (n, fn4(n)))

7、定義一個函數,接收一個列表作為參數,函數用於去除列表中的重復元素。
 1 def no_repeat(sequence):  2     my_list = []  3     for s in sequence:  4         if s not in my_list:  5  my_list.append(s)  6     return my_list  7 
 8 def no_repeat_2rd(sequence):  9     """利用字典的 fromkeys 方法,將列表的元素轉換為字典的鍵, 10  因字典的鍵不能重復,通過獲取字典的鍵列表,就是去重后的列表"""
11     my_list = list({}.fromkeys(sequence).keys()) 12     return my_list 13 
14 seq = ['a', 'java', 'c', 'python', 'c', 'stark', 'michael', 'c', 'a', 'python'] 15 print(no_repeat_2rd(seq)) 16 
17 輸出: 18 ['a', 'java', 'c', 'python', 'stark', 'michael']

8、定義一個函數 fn5(n) ,用於返回一個包含 n 個不重復的 0~100 之間整數的元組。
注意:輸入的整數大於100時,程序會陷入死循環。
 1 import random  2 
 3 def fn5(n):  4     i, my_list =0, []  5     while True:  6         temp_num = random.randint(0, 100)  7         if temp_num not in my_list:  8  my_list.append(temp_num)  9             i += 1
10         if i == n: 11             break       # 結束循環
12     return tuple(my_list) 13 
14 n = int(input("請輸入一個整數:")) 15 my_tuple = fn5(n) 16 print("元組元素個數是:%d" % len(my_tuple)) 17 print(my_tuple)

9、定義一個函數 fn6(n),該函數返回一個包含 n 個不重復的大寫字母的元組。
 1 import random  2 def fn6(n):  3     i, my_list =0, []  4     while True:  5         num = random.randint(65, 90)  6         s = chr(num)  7         if s not in my_list:  8  my_list.append(s)  9             i += 1
10         if i == n: 11             break
12     return tuple(my_list) 13 
14 n = int(input("請輸入一個整數:")) 15 print(fn6(n))

10、定義一個函數 fn7(n),參數 n 表示一個 n 行 n 列的矩陣。在輸出時,先輸出 n 行 n 列的矩陣,再輸出該矩陣的轉置形式。例如參數是3時,先輸出
1 2 3
4 5 6
7 8 9
再輸出:
1 4 7
2 5 8
3 6 9
 1 def fn7(n):  2     # 輸出矩陣
 3     for i in range(n):  4         for j in range(n):  5             print(" %2d " % (1 + j + i * n), end="")  6         print()  7     print("-" * (4 * n))  8 
 9     # 輸出轉置矩陣
10     for i in range(n): 11         for j in range(n): 12             print(" %2d " % (1 + i + j * n), end="") 13         print() 14 n = int(input("請輸入整數:")) 15 fn7(n)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM