Python開發【第四篇】函數
阿新 • • 發佈:2018-08-15
鍵值 utf-8 nonlocal auth for循環 lambda test 覆蓋 我會
函數的作用
函數可以讓編程邏輯結構化以及模塊化
無論是C、C++,Java還是Python,函數是必不可少的知識點,也是很重要的知識點,函數是完成一個功能的代碼塊,使用函數可以使邏輯結構變得更加清晰以及程序模塊化設計
先來看看Python函數相關知識
1 def test(x): 2 """我是用來描述這個函數的""" 3 x += 1 4 return x 5 6 # def : 定義函數的關鍵字 7 # test: 函數名 8 # (): 裏面定義形參 9 # """ """: 用來描述這個函數的功能以及所傳函數,返回值,10 # x+= 1: 函數執行的代碼塊 11 # return :定義返回值
函數的的運行:函數名() 只有加上這個括號才是運行這個函數
函數運行的結束
當函數執行遇到return,後面所有的代碼都是無效的,都不會執行
def test(): print(‘我會打印‘) return print(‘我不會被打印‘) test() """ 我會打印 """
函數參數:
- 形參:只在函數內部有效
- 實參:
- 位置參數和關鍵字參數
- 默認參數
- 參數組
__author__ = "Tang" # 形參:x y zdef test(x,y,z): print(x) print(y) print(z) test(1,2,3) # 實參:1,2,3 # 位置參數 一一對應 def test(x,y,z): print(x) print(y) print(z) test(1,2,3) # # test(1,2) # 缺一不可 報錯 # test(1,2,3,4) # 多一不可 報錯 # 關鍵字參數 def test(x,y,z): print(x) # 2 print(y) # 1 print(z) # 3 test(y=1,x=2,z=3) # 位置參數 & 關鍵字參數 混搭 # 位置參數一定要在關鍵字的左邊 def test(x,y,z): print(x) # 2 print(y) # 1 print(z) # 3 # test(1,3,y=2) # 報錯 位置參數必須一一對應 test(1,y=3,z=2) # test(1,3,z=2,y=3) # 報錯,傳入參數比形參多 沒有覆蓋一說 # x,z 為默認參數 def test(x,y=1,z=3): print(x,y,z) test(10) # 10 1 3默認參數不傳 使用默認的 test(10,20,30) # 10 20 30 如果傳了就覆蓋 # 不定參數 # 參數組: * 列表 元組, **字典 鍵值對 # 第一種 def test(x,*args): print(x) # 1 print(args) # (2, 3, 4, 5) print(*args) # 2 3 4 5 註意:這裏沒有換行 test(1,2,3,4,5) # 第二種 *() def test(x,*args): print(x) # 1 print(args) # ((2, 3, 4, 5, 6) print(*args) # 2 3 4 5 6 註意:這裏沒有換行 test(1,2,3,*(4,5,6)) # 第三種 () def test(x,*args): print(x) # 1 print(args) # ((2, 3, (4, 5, 6)) print(*args) # 2 3 (4, 5, 6) 註意:這裏沒有換行 test(1,2,3,(4,5,6)) # 第四種 [] def test(x,*args): print(x) # 1 print(args) # (2, 3, [4, 5, 6]) print(*args) # 2 3 [4, 5, 6] 註意:這裏沒有換行 test(1,2,3,[4,5,6]) # 第五種 *[] def test(x,*args): print(x) # 1 print(args) # ((2, 3, 4, 5, 6) print(*args) # 2 3 4 5 6 註意:這裏沒有換行 test(1,2,3,*[4,5,6]) # **kwargs 字典 鍵值對 # 第一種 def test(x,**kwargs): print(x) # 1 print(kwargs) # {‘y‘: 2, ‘z‘: 3} # print(**kwargs) # 報錯 test(1,y=2,z=3) # 第二種 def test(x,**kwargs): print(x) # 1 print(kwargs) # {‘y‘: 2, ‘z‘: 3} # print(**kwargs) # 報錯 # test(1,{"y":2,"z":3}) # 報錯 test(1,**{"y":2,"z":3})
函數裏面可以調用函數
__author__ = "Tang" def test1(): print(‘我是test1‘) def test2(): print(‘我是test2‘) test1() test2() """ 我是test2 我是test1 """
全局變量與局部變量
- 全局變量一般都是大寫 ,在整個程序中都可以被訪問
- 局部變量,定義在代碼塊中,for循環,函數等
__author__ = "Tang" name = "我是全局變量" # def test(): name = "我是局部變量" print(name) # 我是局部變量 test() print(name) # 我是全局變量
以上例子可以看到,當局部變量和全局變量都為同一個變量名的時候,在代碼塊裏面,首先先找代碼塊中的變量也就是局部變量,當代碼塊中找不到該變量,就找全局變量
name = "我是全局變量" # def test(): print(name) # 我是全局變量 test() print(name) # 我是全局變量
在代碼塊中修改全局變量需要用到關鍵字 global
name = "我是全局變量" # def test(): global name name = "我是全局變量,我被修改啦" print(name) # 我是全局變量,我被修改啦 test() print(name) # 我是全局變量,我被修改啦
請註意看我哦!
name = "我是全局變量" def test(): global name print(name) # 我是全局變量 name = "我是全局變量,我被修改啦" print(name) # 我是全局變量,我被修改啦 test() print(name) # 我是全局變量,我被修改啦
總結:當找不到代碼塊中的變量,就會到上一級中找該變量。當看到global 關鍵字,就要想到要重修賦值全局變量。如果沒有global關鍵字,只能讀取全局變量,無法重新賦值全局變量的值。
下面請註意
當全局變量為可變數據類型的時候,可在代碼塊中對全局變量進行修改(增,刪,改),但是不能對全局變量進行重新賦值,賦值的只是局部變量,除非用global 關鍵字進行聲明為全局變量,此時才是賦值給全局變量
# 第六種 列表添加 NAME = ["tang","lao"] def test(): NAME.append(‘er‘) print(NAME) # [‘tang‘, ‘lao‘, ‘er‘] test() print(NAME) # [‘tang‘, ‘lao‘, ‘er‘] # 第七種 列表刪除 NAME = ["tang","lao",‘er‘] def test(): NAME.remove(‘er‘) print(NAME) # [‘tang‘, ‘lao‘] test() print(NAME) # [‘tang‘, ‘lao‘] # 第八種 列表修改 NAME = ["tang","lao",‘er‘] def test(): NAME[0] = "chen" print(NAME) # [‘chen‘, ‘lao‘, ‘er‘] test() print(NAME) # [‘chen‘, ‘lao‘, ‘er‘] # 第九種 字典 修改 NAME = {"name":"tang","age":18} def test(): NAME["name"] = "chen" print(NAME) # {‘name‘: ‘chen‘, ‘age‘: 18} test() print(NAME) # {‘name‘: ‘chen‘, ‘age‘: 18} # 第九種 字典 添加 NAME = {"name":"tang","age":18} def test(): NAME["hobby"] = "girl" print(NAME) # {‘name‘: ‘tang‘, ‘age‘: 18, ‘hobby‘: ‘girl‘} test() print(NAME) # {‘name‘: ‘tang‘, ‘age‘: 18, ‘hobby‘: ‘girl‘} # 第九種 字典 刪除 NAME = {"name":"tang","age":18} def test(): del NAME["name"] print(NAME) # {‘age‘: 18} test() print(NAME) # {‘age‘: 18}
# 沒有global 賦值 NAME = {"name":"tang","age":18} def test(): NAME = {‘a‘:1,‘b‘:2} print(NAME) # {‘a‘: 1, ‘b‘: 2} test() print(NAME) # {‘name‘: ‘tang‘, ‘age‘: 18} # 有global 賦值 NAME = {"name":"tang","age":18} def test(): global NAME NAME = {‘a‘:1,‘b‘:2} print(NAME) # {‘a‘: 1, ‘b‘: 2} test() print(NAME) # {‘a‘: 1, ‘b‘: 2}
一個錯誤的特例
__author__ = "Tang" # 錯誤的例子 報錯 # NAME = [‘tang‘,‘lao‘,‘er‘] # def test(): # NAME = "chen" # global NAME # print(NAME) # test() # print(NAME) # 改正 NAME = "tang" def test(): global NAME # 我是聲明 我要在 NAME 其他操作的前面 NAME = "chen" print(NAME) # chen test() print(NAME) # chen
總結:聲明要在其他操作的前面,不然會報錯。。。。。。
為了防止錯誤,全局變量大寫,局部變量小寫,可以防止編程出現沒必要的錯誤
函數嵌套
1 __author__ = "Tang" 2 3 # 函數嵌套 4 NAME = "全局" 5 def yeye(): 6 name = "爺爺級別" 7 print(name) 8 def fu(): 9 name = "父級別" 10 print(name) 11 def zi(): 12 name = "子級別" 13 print(name) 14 def sunzi(): 15 name = "孫子級別" 16 print(name) 17 sunzi() 18 zi() 19 fu() 20 yeye() 21 print(NAME) 22 23 """ 24 爺爺級別 25 父級別 26 子級別 27 孫子級別 28 全局 29 """
再來一個,請仔細看
name = "A" def test(): name = "B" def test_test(): global name name = "C" test_test() print(name) # B print(name) # A test() print(name) # C
關鍵字 nonlocal 聲明上一級的變量
name = "A" def test(): name = "B" def test_test(): nonlocal name # nonlocal,指定上一級變量 name = "C" test_test() print(name) # C print(name) # A test() print(name) # A
nonlocal 只能使用於兩級或多級函數嵌套,一級嵌套會導致程序報錯,下面請看一個錯誤的示例
name = "A" def test(): nonlocal name # 報錯 name = "C" print(name) print(name) test() print(name)
函數聲明與調用的順序
函數即變量,調用函數前需先聲明
# 第一種情況 def foo(): print("foo") bar() def bar(): print("bar") foo()
下面看一個錯誤的例子
# 第二種情況 報錯的例子 def foo(): print("foo") bar() foo() def bar(): print("bar")
函數遞歸
- 必須有一個明確的結束條件(if 判斷)return結束
- 每次進入更深一層遞歸時,問題規模相比上一次遞歸都應有所減少
1 __author__ = "Tang" 2 3 def calc(n): 4 print(n) 5 if int(n / 2) ==0: 6 return n 7 res = calc(int(n/2)) 8 print("****",res) 9 return res 10 n = calc(10) 11 print(n) 12 """ 13 10 14 5 15 2 16 1 17 **** 1 18 **** 1 19 **** 1 20 1 21 """
遞歸代碼練習:一個快速排序的例子
1 # coding:utf-8 2 def quick_sort(alist, first, last): 3 """快速排序""" 4 if first >= last: 5 return 6 mid_value = alist[first] 7 low = first 8 high = last 9 while low < high: 10 # high 左移 11 while low < high and alist[high] >= mid_value: 12 high -= 1 13 alist[low] = alist[high] 14 15 while low < high and alist[low] < mid_value: 16 low += 1 17 alist[high] = alist[low] 18 # 循環退出時,滿足條件low==high 19 alist[low] = mid_value 20 21 # 對low左邊的列表執行快速排序 22 quick_sort(alist, first, low-1) 23 24 # 對low右邊的列表排序 25 quick_sort(alist, low+1, last) 26 27 28 if __name__ == "__main__": 29 li = [54, 26, 93, 17, 77, 31, 44, 55, 20] 30 print(li) 31 quick_sort(li, 0, len(li)-1) 32 print(li)
斐波那契數列
__author__ = "Tang" # 斐波那契數列 a = 0 b = 1 while b < 1000: print(b,end=" ") a,b = b, a+b # 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 # 生成前20項 lis =[] for i in range(20): if i ==0 or i ==1:# 第1,2項 都為1 lis.append(1) else: lis.append(lis[i-2]+lis[i-1])# 從第3項開始每項值為前兩項值之和 print(lis) # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765] # 遞歸實現 li = [] def test(a, b): if a > 1000 or b > 2000: return li.append(a) li.append(b) a = a + b b = a + b test(a, b) test(1, 1) print(li) # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]
函數作用域相關練習
1 __author__ = "Tang" 2 3 """函數的作用域相關練習""" 4 5 """ 6 尋找變量的順序:當前函數裏面尋找,如果找不到就往上一層函數找,實在找不到就找全局變量 7 函數的調用:函數名+ () 函數名即變量,只要取得函數地址就可以 8 """ 9 10 # 第一種 11 def foo(): 12 print("我是foo") 13 def bar(): 14 print("我是bar") 15 bar() 16 foo() 17 # bar() # 報錯 不可以直接調用 記住:要想執行裏面的,就要先執行外面的,想象盒子裏面包含盒子,外面的盒子不拿掉,裏面的也拿不出來 18 """ 19 我是foo 20 我是bar 21 """ 22 23 # 第二種 24 def foo(): 25 print("我是foo") 26 def bar(): 27 print("我是bar") 28 return bar 29 test = foo() 30 test() # 可以調用 test拿到bar函數的地址 31 """ 32 我是foo 33 我是bar 34 """ 35 36 # 第三種 37 def test(): 38 print("我是test") 39 print(test()) # 沒有沒有返回值 默認為None 40 """ 41 我是test 42 None 43 """ 44 45 # 第四種 46 def test(): 47 print("我是test") 48 return 10 49 print(test()) 50 """ 51 我是test 52 10 53 """ 54 55 # 第五種 56 name = "tang" 57 def foo(): 58 name = "chen" 59 def bar(): 60 name = "li" 61 print(name) 62 return bar 63 a = foo() 64 print(a) 65 a() 66 """ 67 <function foo.<locals>.bar at 0x02FE0B28> 68 li 69 """ 70 71 # 第六種 72 name = "tang" 73 def foo(): 74 name = "chen" 75 def bar(): 76 print(name) 77 return bar 78 a = foo() 79 print(a) 80 a() 81 """ 82 <function foo.<locals>.bar at 0x00830B70> 83 chen 84 """ 85 86 # 第七種 87 name = "tang" 88 def foo(): 89 name = "chen" 90 def bar(): 91 print(name) 92 return bar 93 foo()() 94 """ 95 chen 96 """
匿名函數 lambda
lambda x : x+1 一個簡單的匿名函數
__author__ = "Tang" def test(x): return x + 1 res = test(10) print(res) # 11 # 匿名函數實現上面函數 func = lambda x:x+1 print(func(10)) # 11
下面通過一些簡單的例子來加深匿名函數的理解
# 第一個 name = "tang" def change_name(x): return x +"_sb" res = change_name(name) print(res) # tang_sb res = lambda x:name+"_sb" print(res(name)) # tang_sb print(res("tang")) # tang_sb res = lambda x:x+"_sb" print(res(name)) # tang_sb print(res("tang")) # tang_sb # 第二個 傳多個參數 func = lambda x,y,z:x+y+z print(func(1,2,3)) # 6 # 第三個 name1 = "tang" name2 = "lao" name3 = "er" x = lambda name1,name2,name3:"".join([name1,name2,name3]) print(x(name1,name2,name3)) # tanglaoer
Python開發【第四篇】函數