第一部分:函數,參數及參數解構
一.什么是函數
1.函數
(1)數學定義:y=f(x),y是x的函數,x是自變量
(2)python函數:由若干語句組成的語句塊,函數名稱,參數列表構成,它是組織代碼的最小單元,完成一定的功能。可以通過函數名在程序的不同地方多次執行(這通常叫做函數調用),卻不需要在所有地方都重復編寫這些語句。
2.函數的作用
(1)結構化編程對代碼的最基本的封裝,一般按照功能組織一段代碼
(2)瘋轉的目的為了復用,減少冗余代碼
(3)代碼更加簡潔美觀,可讀易懂
(4)可擴展性
3.函數的分類
(1)內建函數,如max(),reversed()等
(2)庫函數,如math.ceil()等
二.函數定義和調用
1.函數定義方法:
(1)語法:def語句定義函數
def 函數名(參數列表) 函數體(代碼塊) [return返回值]
(1)函數名就是標識符,命名要求一樣
(2)語句塊必須縮進,約定4個空格
(3)python的函數沒有return語句,隱式會返回一個None值
(4)定義中的參數列表成為一個形式參數,只是一種符號表達,簡稱形參
(5)代碼:
def test(x): #def:定義函數的關鍵字,test是函數名,(x)內可定義形參 "函數注釋" #"文檔描述":文檔描述(非必要,但是強烈建議為你的函數添加描述信息) x+=1 #x+=1:泛指代碼塊或程序處理邏輯 return x #return:定義返回值,函數碰到return整體結束掉 a=test(x) #變量a=函數名():調用運行(可以帶參數也可以不帶) print(a) #輸出a
2.調用
(1)函數定義,只是聲明了一個函數,它不會被執行,需要調用
(2)調用的方式,就是函數名加上小括號,括號內寫上參數
(3)調用時寫的參數是實際參數,是實實在在傳入的值,簡稱實參
3.函數定義調用舉例
def test(x): ''' :功能:y=2*x+1 :param x:整型數字 :return y:返回計算結果 ''' y=2*x+1 return y a=test(5) print(a) #運行返回:11
總結:
(1)上面只是一個函數的定義,有一個函數叫test,接收1個參數
(2)計算的結果,通過返回值返回
(3)調用通過函數名test加1個參數,返回值可使用變量接收
(4)定義需要在調用前,也就是說調用時,已經被定義過了,否則拋NameError異常
(5)函數是可以調用的對象,callable()
4.為什么使用函數
(1)降低編程的難度
(2)代碼重用
(3)可擴展性
三.函數和過程
1.過程:過程就是簡單特殊沒有返回值的函數
2.當一個函數/過程沒有使用return顯示的定義返回值時,python解釋器會隱式的返回None,在python中即便是過程也可以算作函數。
舉例1:
def test1(): #定一個過程沒有return msg='hello xi' print msg def test2(): #定一個函數有return msg='hello xixi' print msg return msg t1=test1() t2=test2() print 'from test1 return is [%s]' %t1 print 'from test2 return is [%s]' %t2 輸出結果: hello xi hello xixi from test1 return is [None] from test2 return is [hello xixi]
舉例2:
def test1(): msg = 'test1' print(msg) def test2(): msg = 'test2' print(msg) return msg def test3(): msg = 'test3' print(msg) return 0,10,'hello',['xixi','xixi'],{'wang':'xixi'} t1=test1() #首先運行test1() 把結果賦值給t1 t2=test2() #test2() 把結果賦值給t2 t3=test3() #test3() 把結果賦值給t3 print (t1) #取t1執行test1的執行結果 print (t2) #取t2執行test2的執行結果 print (t3) #取t2執行test3的執行結果 輸出結果: test1 test2 test3 None test2 (0, 10, 'hello', ['xixi', 'xixi'], {'wang': 'xixi'})
總結:
返回值數=0:返回None
返回值數=1:返回object
返回值數>1:返回tuple
四.函數參數
1.分位置參數和關鍵字參數
(1)位置參數:
1)方式:def f(x,y,z)調用使用f(1,3,5)
2)按照參數定義順序傳入實參:
實參可以是常量、變量、表達式、函數等,無論實參是何種類型的量,在進行函數調用時,它們都必須有確定的值,以便把這些值傳送給形參。因此應預先用賦值,輸入等辦法使參數獲得確定值
(2)關鍵字參數
1)方式:def f(x,y,z)調用使用f(x=1,y=3,z=5)
2)使用形參的名字來出入實參的方式,如果使用了形參名字,那么傳參順序就可和定義順序不同
形參變量只有在被調用時才分配內存單元,在調用結束時,即刻釋放所分配的內存單元。因此,形參只在函數內部有效。函數調用結束返回主調用函數后則不能再使用該形參變量
(3)傳參
關鍵字命名參數傳參:f(z=None,y=10,x=[1])
位置參數+關鍵字命名參數傳參:f((1,),z=6,y=4.1)
f(y=5,z=6,2):傳參失敗:要求位置參數必須在關鍵字參數之前傳入,位置參數是按位置對應的
注意:動態行語言,傳實參不強求傳的參數是什么類型
2.函數參數默認值(簡化工作)
(1)參數默認值:定義時,在形參后跟上一個值
(2)舉例
<1>x,y不傳參數,用默認值
def add(x=4,y=5): return x+y xx = add() print(xx) 返回: 9
<2>x位置傳參數6,y不傳參數用默認的
def add(x=4,y=5): return x+y xx = add(6) print(xx) 返回: 11
<3>x,y關鍵字命名參數給默認值參數傳參
def add(x=4,y=5): return x+y xx = add(y=6,x=7) print(xx) 返回: 13
<4>傳的位置參數不允許在關鍵字參數后面(報錯)
def add(x=4,y=5): return x+y xx = add(y=6,1) print(xx)
<5>缺省值參數(位置參數)不允許在關鍵字參數后面(報錯)
def add(x=4,y): return x+y
(3)參數的默認值作用:
參數的默認值可以在未傳入足夠的實參的時候,對沒有給定的參數賦值的默認值
參數非常多的時候,並不需要用戶每次都輸入所有的參數,簡化函數調用
3.可變參數
(1)位置參數的可變參數
舉例:有多個數,需要累加求和
def add(*nums): #在形參nums前使用*表示該形參是可變參數 xx = 0 print(type(nums)) #收集多個或0個實參為一個tuple(元祖) for x in nums: xx += x print(xx) #調用add函數傳3,6,9 add(3,6,9) 返回: <class 'tuple'> 18
(2)關鍵字參數的可變參數
def showconfig(**kwargs): #形參前使用**符號,表示可以接收多個關鍵字參數 print(type(kwargs)) #收集的實參名稱和值組成一個字典 for k,v in kwargs.items(): print('{} = {}'.format(k,v)) ##調用showconfig函數傳host='127.0.0.1',port='8080',username='xixi',password='123456' showconfig(host='127.0.0.1',port='8080',username='xixi',password='123456') 返回: <class 'dict'> username = xixi password = 123456 port = 8080 host = 127.0.0.1
(3)可變參數混合使用
舉例:位置參數xixi,位置參數的可變參數123,關鍵字參數的可變參數x=1,y=2混合使用
def showconfig(username,*args,**kwargs): print(username) print(args) print(kwargs) showconfig('xixi',123,x=1,y=2) 返回: xixi (123,) {'x': 1, 'y': 2}
(4)可變參數總結:
有位置可變參數和關鍵字可變參數
位置可變參數在形參前使用一個星號*
關鍵字可變參數在形參前使用兩個星號**
位置可變參數和關鍵字可變參數都可以收集若干個實參,位置可變參數收集形成一個tuple,關鍵字可變參數收集形成一個dict
混合使用參數的時候,可變參數要放到參數列表的最后,普通參數需要放到參數列表前面,位置可變參數需要在關鍵字可變參數之前
4.keyword-only參數
(1)keyword-only參數(python3加入)
如果在一個星號參數后,或者一個位置可變參數后,出現的普通參數,實際上已經不是普通的參數了,而是keyword-only參數
def fn(*args,x): #args截獲了所有的位置參數,x不使用關鍵字參數就不可能拿到實參,x是keyword-only參數 print(x) print(args) #調用fn函數傳3,5,7,x=1 fn(3,5,7,x=1) 返回: 1 (3, 5, 7)
(2)keyword-only參數另一種形式
def fn(*,x,y): #*號之后,普通形參都變成了必須給出的keyword-noly參數 print(x,y) fn(x=5,y=6) 返回: 5 6
5.可變參數和默認值參數結合使用
舉例1:可變參數不傳值,默認參數不傳值
def fn(*args,x=5): print(args) print(x) fn() #等價於fn(x=5) 返回: () 5
舉例2:可變參數傳值,默認參數不傳值
def fn(*args,x=5): print(args) print(x) fn(6) 返回: (6,) 5
舉例3:可變參數不傳值,默認參數傳值
def fn(*args,x=5): print(args) print(x) fn(x=6) 返回: () 6
舉例4可變參數傳值,默認參數傳值
def fn(*args,x=5): print(args) print(x) fn(1,2,3,x=6) 返回: (1, 2, 3) 6
6.函數參數規則
參數列表參數一般順序是,普通參數,缺省參數,可變位置參數,keyword-only參數(可帶缺省值),可變關鍵字參數
7.參數解構
(1)參數解構:
給函數提供實參的時候,可以在集合類型前使用*或者**,把集合類型的解構解開,提取出所有元素作為函數的實參
非字典類型使用*解構成關鍵參數
字典類型使用**解構成關鍵字參數
提取出來的元素數目要喝參數的要求匹配,也要和參數的類型匹配
(2)法函數
舉例:
def add(x,y): return x + y #解構(2,3)[0]元祖傳第一個元素2,[3][0]列表傳第一個元素3 xx = add((2,3)[0],[3][0]) print(xx) 返回: 5
舉例:解構元祖
def add(x,y): return x + y #把多個元素的集合(4,5)結構后傳到add函數里 xx = add(*(4,5)) print(xx) 返回: 9
舉例:解構列表
def add(x,y): return x + y #把多個元素的列表[4,5]結構后傳到add函數里 xx = add(*[4,5]) print(xx) 返回: 9
舉例:解構可迭代對象
def add(x,y): return x + y #把range(1,3)可迭代對象結構后傳到add函數里 xx = add(*range(1,3)) #個數要跟形參一一匹配 print(xx)
舉例:解構字典
def add(x,y): return x + y d = {'a':5,'b':6} #把字典{'a':5,'b':6}結構后傳到add函數里 xx = add(*d.values()) print(xx) 返回: 11
8.參數解構和可變參數
給函數提供實參的時候,可以在集合類型前使用*或者**,把集合類型的結構解開,提取出所有元素作為函數的實參
舉例:解構列表+可變參數
def add(*iterble): result = 0 for x in iterble: result += x return result #解構[1,2,3]傳到函數add的可變參數 xx = add(*[1,2,3]) print(xx) 返回: 6
舉例:解構可迭代對象+可變參數
def add(*iterble): result = 0 for x in iterble: result += x return result #range(5)可迭代對象傳到函數add的可變參數 xx = add(*range(5)) print(xx) 返回: 10
9.練習:
編寫一個函數,能夠隨機接收隨機十個數,返回最小值和最大值
import random def double_values(*nums): print(nums) return max(nums),min(nums) #列表解析隨機生成10個10到20的數字的列表:([random.randint(10,20) for _ in range(10)])再通過*解構得到10到20個數字傳的實參 #把return max(nums),min(nums)返回的元祖解構通過*解構成兩個數字 print(*double_values(*[random.randint(10,20) for _ in range(10)])) #把實參傳到可變參數里得到的元祖解構成兩個數字 返回: (15, 11, 17, 16, 10, 13, 18, 12, 14, 14) 18 10
編寫一個函數,接收有一個參數n,n為正整數,左右兩種打印方式。要求數字必須對齊
右對齊方式:
def show(n): tail = " ".join([str(i) for i in range(n,0,-1)]) #計算出最后一行字符串12 11 10 9 8 7 6 5 4 3 2 1 width = len(tail) #算出最后一行字符串的寬度 for i in range(1,n): #(" ".join([str(j) for j in range(i,0,-1)]))每循環一遍減去一個數字 #width最后一行字符串的寬度26,也就是每行的總寬度 #("{:>{}}".format(每次循環減去一個數字)),把每次循環減一個數字傳到{}按右對齊 print("{:>{}}".format(" ".join([str(j) for j in range(i,0,-1)]),width)) print(tail) show(12) 輸出: 1 2 1 3 2 1 4 3 2 1 5 4 3 2 1 6 5 4 3 2 1 7 6 5 4 3 2 1 8 7 6 5 4 3 2 1 9 8 7 6 5 4 3 2 1 10 9 8 7 6 5 4 3 2 1 11 10 9 8 7 6 5 4 3 2 1 12 11 10 9 8 7 6 5 4 3 2 1
左對齊方式:
def showtail(n): tail = " ".join([str(i) for i in range(n,0,-1)]) #計算出最后一行字符串12 11 10 9 8 7 6 5 4 3 2 1 print(tail) #打印首行:12 11 10 9 8 7 6 5 4 3 2 1 for i in range(len(tail)): #把符串從頭到尾迭代一遍 if tail[i] == ' ': #12 11 10 9 8 7 6 5 4 3 2 1從做到右如果發現一個空格 print(' '*i,tail[i+1:]) #把發現空格前面的數字替換成一個空格 showtail(12) 輸出: 12 11 10 9 8 7 6 5 4 3 2 1 11 10 9 8 7 6 5 4 3 2 1 10 9 8 7 6 5 4 3 2 1 9 8 7 6 5 4 3 2 1 8 7 6 5 4 3 2 1 7 6 5 4 3 2 1 6 5 4 3 2 1 5 4 3 2 1 4 3 2 1 3 2 1 2 1 1
第二部分:函數的返回值
一.函數返回值
1.特點
(1)python函數使用return語句返回“返回值”
(2)所有函數都有返回值,如果沒有return語句,隱式調用return None
(3)return語句並不一定是函數的語句塊的最后一條語句
(4)一個函數可以存在多個return語句,但是只有一條可以被執行。如果沒有一條return語句被執行到,隱式調用return None
(5)如果有必要可以顯示調用return None,可以簡寫為return
(6)如果函數執行了return語句,函數就會返回,當前被執行的return語句之后的其它語句就不會被執行了
2.作用:結束函數調用,返回值
舉例:
def fn(x): for i in range(x): if i > 3: return i #當4大於3的時候返回4 else: print("{}不大於3".format(i)) print(fn(5)) 返回: 0不大於3 1不大於3 2不大於3 3不大於3 4
舉例:
def fn(x): for i in range(x): if i > 3: #沒有執行到return語句返回None return i else: print("{}不大於3".format(i)) print(fn(3)) 返回: 0不大於3 1不大於3 2不大於3 None
3.返回多個值
(1)函數不能同時返回多個值
(2)return[1,3,5]是指明返回一個列表,是一個列表對象
(3)recent1,3,5看似返回多個值,隱式的被python封裝成一個元祖
def showlist(): return 1,3,5 x,y,z = showlist() #使用解構提取更為方便 print(x,y,z) 返回: 1 3 5
第三部分:嵌套函數
1.函數嵌套:在一個函數中定義了另外一個函數
(1)函數有可見范圍,這就是作用域的概念
(2)內部函數不能被外部直接使用,會拋NameError異常
2.函數嵌套舉例
(1)舉例1
def outer(): def inner(): print("outer()調用內部") print("inner()調用外部") inner() #內部調用 outer() #外部調用 #inner() #外部不可以直接調用內部函數報錯NameError 打印返回: inner()調用外部 outer()調用內部
(2)舉例2
def one(name): #第一層函數one print('第一層函數%s' %name) #執行當前層的局部變量print('第一層函數%s' %name)和def two(): def two(): #第二層函數two name='shishi' print('第二層函數%s' %name) #打印當前層的局部變量 def three(): #第三層函數three name='yaoyao' print('第三層函數%s' %name) #打印當前層的局部變量 three() #內部調用 two() #內部調用 one('xixi') 打印結果: 第一層函數xixi 第二層函數shishi 第三層函數yaoyao
第四部分:函數柯里化Currying
1.柯里化指的是將原來接受兩個參數的函數變成新的接受一個參數的函數的過程。新的函數返回一個以原有的第二個參數為參數的函數
2.z=f(x,y)轉換成z=f(x)(y)的形式
3.將加法函數柯里化函數
加法函數:
def add(x,y): return x + y xixi = add(5,6) print(xixi) #返回:11
轉換柯里化:
def add(x): #x調add(5)的時候把5傳進去 def _add(y): #第二個參數y對應傳的是6 return x + y #這里可以調用到x,x是外層的變量,里面的函數相當於閉包 return _add #新的函數_add返回一個以原有第二個參數為參數的函數 xixi = add(5)(6) #add(5)返回值相當於函數對象,在傳入一個6 print(xixi) #返回:11
總結:通過嵌套函數可以把函數轉換成柯里化函數
第五部分:函數作用域
一.函數作用域
1.作用域:一個標識符的可見范圍,這就是標識符的作用域,一般常說的是變量的作用域
2.局部作用域:
(1)在當前函數,類等內部可見
(2)局部變量使用范圍不能超過其所在的局部作用域
def fn1(): #函數fn1() x =1 #x=1局部作用域,在fn1內 def fn2(): #函數fn2() print(x) #不可見x print(x) #不可見x
3.全局作用域:在整個程序運行環境中都可見
name='全局作用域' def change_name(): print('change_name',name) #函數內全局作用域 change_name() print(name) #函數外調用全局作用域 打印結果: change_name 全局作用域 全局作用域
4.作用域嵌套結構
舉例1:foo函數內嵌了一個bar函數
name = '全局作用域' def foo(): name='局部作用域' def bar(): print(name) return bar a=foo() print(a) a() #返回結果: <function foo.<locals>.bar at 0x00000000011989D8> 局部作用域
執行詳解1:a=foo()和print(a)運行過程詳解:執行foo()首先運行:①name='局部變量'②加載了個函數def bar():到內存當中 ③return bar了一個結果,賦值給a,print(a)打印獲得bar的內存地址
執行詳解2:a()運行過程詳解:有了bar的內存地址就可以運行bar()這個函數了,這個函數有個print(name),執行a()相當於執行bar()這個函數,不管a()在那個位置調用bar()這個函數,函數在運行當中的作用域都跟定義的時候有關
舉例2:外層變量作用域在內層作用域可見
def outer1(): o = 65 def inner(): print("inner{}".format(o)) #內層作用域可用外層變量 print(chr(o)) print("outer{}".format(o)) #打印調用外層的變量 inner() outer1() #返回結果: outer65 inner65 A
舉例3:內層作用域inner中,如果定義了o=97,相當於當前作用域中重新定義了一個新的變量o,但是這個o並沒有覆蓋外層作用域outer中的o
def outer1(): o = 65 def inner(): o = 97 print("inner{}".format(o)) #內層作用域調用內層從新定義的變量97 print(chr(o)) print("outer{}".format(o)) #o並沒有覆蓋外層作用域outer中的 inner() outer1() #返回結果: outer65 inner97 a
5.全局變量global:把局部變量強制成全局變量
x = 5 def foo(): global x x +=1
(1)使用global關鍵字變量,將foo內的x聲明為使用外部的全局作用域中定義的x
(2)全局作用域中必須有x的定義
(3)如果函數沒有被調用的話 global是沒有用的
舉例:
NAME = "xixi" def s1(): global NAME #已經聲明,NAME就是全局的那個變量xixi NAME = "yueyue" #修改全局的變量為yueyue print('打印出', NAME) def s2(): print('打印出', NAME) s1() s2() #返回結果: 打印出 yueyue 打印出 yueyue
(4)global使用原則
1)外部作用域變量會內部作用域肯建,但也不要在這個內部的作用域中直接使用,因為函數的目的就是為了封裝,盡量與外界隔離
2)如果函數需要使用外部全局變量,清使用函數的形參傳參解決
二.閉包
1.自由變量:未在本地作用域中定義的變量。例如定義在內存函數外的外層函數的作用域中的變量
2.閉包:就是一個概念,出現在嵌套函數中,指的是內層函數引用到了外層函數的自由變量,就形成了閉包。很多語言都有這個概念,最熟悉的就是JavaScript
舉例1:
def counter(): c = [1] #c=[1]是內層inc()函數的自由變量 def inc(): print('當前自由變量',c[0]) c[0] += 1 #引用的是外層counter()函數的變量c= [1] return c[0] return inc foo = counter() print(foo(),foo()) c = 100 print(foo()) #返回結果: 當前自由變量 1 當前自由變量 2 2 3 當前自由變量 3 4
(4)舉例2
def one(name): #one(name)最外層接收xixi print('最外層%s' %name) def two(): #two()中間層:中間層two print('中間層%s' %name) def three(): #three()最里層:閉包three print('最里層%s' %name) three() #執行three()取值在自己的three()最里層閉包里取值 two() #執行two()取值在自己的two()中間層閉包里取值 one('xixi') #最外層傳入xixi #輸出結果:最外層中間層最里層都可以接收到xixi因為他們是層級的關系 最外層xixi 中間層xixi 最里層xixi
三.nonlocal關鍵字(python3后引用):指定上一級變量:如果沒有就繼續往上直到找到為止
(1)使用了nonlocal關鍵字,將變量標記為在上級的局部作用域中定義,但不能是全局作用域定義
(2)舉例:
name = "全局變量" def s1(): name = "局部變量" #外層局部變量被內層name="西西"修改為西西 def ss1(): nonlocal name #把上一級變量name = "局部變量"改為name=西西 name = "西西" ss1() print('2',name) print('1',name) s1() print('3',name) #打印結果: 1 全局變量 2 西西 3 全局變量
四.默認值的作用域
(1)默認值作用域舉例1:外部不可以調用內部默認值
def foo(xyz=1): print(xyz) foo() #print(xyz) #報錯,當前作用域沒有xyz變量,外部不可以調用內部默認值 #返回結果: 1
(2)默認值作用域舉例2:python把函數默認值放在了屬性中
def foo(xyz=[]): #第一次調用foo(),把對象默認值放在特殊的屬性上 #第二次調用foo() xyz.append(1) #給xyz添加1,xyz=[1] #再給xyz添加1,xyz=[1,1] print(xyz) foo() foo() #返回結果: [1] [1, 1]
總結:
1)為什么第二次調用foo函數打印的是[1,1]
2)因為函數也是對象,python把函數的默認值放在了屬性中,這個屬性就伴隨這這個函數對象的整個生命周期
(3)默認值作用域舉例3:查看foo.__defaults__函數對象的屬性
def foo(xyz=[],u='abc',z=123): #作用域在函數內部,形參就是函數的本地變量,沒給值從函數對象的defaults屬性去把缺省值拿回來 xyz.append(100) return xyz print(1,foo.__defaults__) #1 ([], 'abc', 123) print(foo(),id(foo)) #foo()返回:[100] id(foo)返回:1867560 print(2,foo.__defaults__) #2 ([100], 'abc', 123) print(foo(),id(foo)) #foo()返回:[100, 100] id(foo)返回:1867560 print(3,foo.__defaults__) #3 ([100, 100], 'abc', 123) #返回結果: 1 ([], 'abc', 123) [100] 3833640 2 ([100], 'abc', 123) [100, 100] 3833640 3 ([100, 100], 'abc', 123)
總結:
1)函數地址沒有變,就是說函數整個對象的沒有變,調用它,它的屬性__defaults__中使用元祖保存所有默認值
2)xyz默認值是引用類型,引用類型的元素變動,並不是元祖的變化
(4)默認值作用域的兩種方法
方法一:使用影子拷貝創建一個新的對象,永遠不能改變傳入的參數
def foo(xyz=[],u='abc',z=123): #第一次調用從缺省值的屬性里拿到空列表 xyz = xyz[:] #影子拷貝:空列表拷貝出來一份,返回一個新的列表,變成局部變量 xyz.append(1) #新列表追加1 print(xyz) #打印新列表 foo() print(1,foo.__defaults__) #1 ([], 'abc', 123) foo() print(2,foo.__defaults__) #2 ([], 'abc', 123) foo([10]) print(3,foo.__defaults__) #3 ([], 'abc', 123) foo([10,5]) print(4,foo.__defaults__) #4 ([], 'abc', 123) #返回結果: [1] 1 ([], 'abc', 123) [1] 2 ([], 'abc', 123) [10, 1] 3 ([], 'abc', 123) [10, 5, 1] 4 ([], 'abc', 123)
總結:
xyz都是傳入參數或者默認參數的副本,如果就想修改參數,無能為力
方法二:使用不可變類型默認值(常用)
1)如果使用缺省值None就創建一個列表
2)如果傳入一個列表,就修改這個列表
3)通過值的判斷就可以靈活的選擇創建或者修改傳入對象
4)這種方式靈活,應用廣泛
5)很多函數的定義,都可以看到使用None這個不可變的值作為默認參數,可以說這是一種慣用法
舉例1
def foo(xyz=None,u='abc',z=123): #第一次調用沒有傳值,調用缺省值,當前缺省值是None if xyz is None: #如果是None xyz = [] #給xyz從新賦值 xyz.append(1) print(xyz) #打印列表里的內容 foo() print(1,foo.__defaults__) #1 (None, 'abc', 123) foo() print(2,foo.__defaults__) #2 (None, 'abc', 123) foo([10]) print(3,foo.__defaults__) #3 (None, 'abc', 123) foo([10,5]) print(4,foo.__defaults__) #4 (None, 'abc', 123) #返回結果: [1] 1 (None, 'abc', 123) [1] 2 (None, 'abc', 123) [10, 1] 3 (None, 'abc', 123) [10, 5, 1] 4 (None, 'abc', 123)
總結:
如果使用缺省值None就出安靜一個列表
如果傳入一個列表,就修改這個列表
舉例2:
def foo(xyz=None,u='abc',z=123): #2.第一次調用沒有傳值,調用缺省值,當前缺省值是None #9.第二次傳有值不用缺省值,xyz不是None if xyz is None: #3.如果是None xyz = [] #4.給xyz從新賦值產生空列表 xyz.append(1) #5.給空列表加一個元素[1] #10.給列表[1]加一個元素變為[1,1] return xyz #6.把[1]返回 #11.把[1,1]返回 lst = foo() #1.調用foo函數 #7.lst接收[1] a = foo(lst) #8.調用foo函數把[1]傳進去 print(a) #12打印[1,1] #返回結果: [1, 1]
五.函數即變量
def test1(): #定義了個變量test1() print 'in the test1' test2() #test1()這個變量定義了一個不存在的變量test2()(內存不存在) def test2(): #把test2()變量又定義了出來(內存里就存在了) print 'in the test2' test1() #返回結果: in the test1 in the test2
name = '全局變量' #第1步執行 def s1(): #第2步執行 name = "嵌套1" #第4.1步執行 print(name) #第4.2步執行(輸出第二行) def s2(): #第4.3步執行 name = "嵌套2" #第4.4.1步執行 print(name) #第4.4.2步執行(輸出第三行) def s3(): #第4.4.3步執行 name = '嵌套3' #第4.4.5.1步執行執行 print(name) #第4.4.5.2步執行(輸出第五行) print(name) #第4.4.4步執行(輸出第四行) s3() #第第4.4.5步執行步執行 s2() #第4.4步執行 print(name) #第4.5步執行(輸出第六行) print(name) #第3步執行(輸出第一行) s1() #第4步執行 print(name) #第5步執行(輸出第七行) #返回結果: 全局變量 嵌套1 嵌套2 嵌套2 嵌套3 嵌套1 全局變量
六.函數的銷毀
1.全局函數銷毀
(1)重新定義同名函數
(2)del語句刪除函數對象
(3)程序結束時
2.局部函數
(1)重新在上級作用域定義同名函數
(2)del語句刪除函數對象
(3)上級作用域銷毀時
七.變量名解析原則LEGB
1.Local,本地作用域,局部作用域的local命名空間,函數調用時創建,調用結束消亡
2.Enclosing,python2.2時引入了嵌套函數,實現了閉包,這個就是嵌套函數的外部函數的命名空間
3.Global,全局作用域,即一個模塊的命名空間,模塊被import時創建,解釋器退出時消亡。
4.Build-in,內置模塊的命名空間,生命周期從python解釋器啟動時創建到解釋器退出時消亡。例如print(open),print和open都是內置的變量
5.所以一個名次的查找順序就是LEGB
第五部分:python匿名函數lambda
1.匿名函數:是一種快速定義單行的最小函數方法,通常是用來跟其它函數一塊聯合使用,他不是單獨存在,可以用在任何需要函數的地方
1.即沒有名字的函數
(2)python借助Lambda表達式構建匿名函數
2.語法結構:
(1)lambda x:x+1 (lambda的關鍵字加上匿名函數的形參x:x+1)
(2)lambda語句中,冒號前是匿名函數的形參,可以有多個,用逗號隔開,冒號后就是這個函數的返回值(相當於函數直接給你return了個值)
(3)lambda語句構建的其實是一個函數對象
3.特點
(1)使用lambda關鍵字來定義匿名函數
(2)參數列表不需要小括號
(3)冒號是用來分割參數列表和表達式
(4)不需要使用return,表達式的值,就是匿名函數返回值
(5)lambda表達式(匿名函數)只能寫在一行上,被稱為單行函數
4.用途
在高階函數傳參時,使用lambda表達式,往往能簡化代碼
(1)無參函數
標准函數寫法:
def fn(): return 0 print(fn()) #返回:0
匿名函數寫法:
>>> print((lambda:0)()) 0
(2)傳1個形參數函數
標准函數寫法:
def fn(x,y=3): return x+y print(fn(5)) #返回:8
匿名函數寫法:
>>> print((lambda x,y=3:x+y)(5)) #8
(3)傳1個形參1個實參數函數
標准函數寫法:
def fn(x,y=3): return x+y print(fn(5,6)) #返回:11
匿名函數寫法:
>>> print((lambda x,y=3:x+y)(5,6)) 11
(4)傳1個形參加默認值參數
標准函數寫法:
def fn(x,*,y=30): return x+y print(fn(5)) #返回:35
匿名函數寫法:
>>> print((lambda x,*,y=30:x+y)(5)) 35
(5)傳1個形參加1個實參替換默認值參數
標准函數寫法:
def fn(x,*,y=30): return x+y print(fn(5,y=10)) #返回:15
匿名函數寫法:
>>> print((lambda x,*,y=30:x+y)(5,y=10)) 15
(6)可變參數
標准函數寫法:
def fn(*args): return [x for x in args] print(fn(*range(5))) #返回:[0, 1, 2, 3, 4]
匿名函數寫法:
>>> print((lambda *args:[x for x in args])(*range(5))) [0, 1, 2, 3, 4]
(7)可變參數加運算
標准函數寫法:
def fn(*args): return [x + 2 for x in args] print(fn(*range(5))) #返回:[2, 3, 4, 5, 6]
匿名函數寫法:
>>> print((lambda *args:[x+2 for x in args])(*range(5))) [2, 3, 4, 5, 6]
第六部分:遞歸函數
一.遞歸函數
在函數內部,可以調用其他函數。如果在調用一個函數的過程中直接或間接調用自身本身
(1)遞歸:遞歸就是程序調用自身不斷深入嵌套,直到滿足條件退出的一種算法
遞歸特性:
(1)必須有一個明確的結束條件
(2)每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少
(3)遞歸效率不高,遞歸層次過多會導致棧溢出(在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出)
1.函數執行流程
#全局幀中生成foo1,foo2,foo3,main函數對象 def foo1(b,b1=3): print("foo1 called",b,b1) #第四步:print函數壓棧,字符串和變量b,b1壓棧,調用函數,彈出棧頂,返回值 def foo2(c): foo3(c) #第六步:foo3函數壓棧,變量c引用壓棧,調用foo3,創建棧幀 print("foo2 called",c) #第八步:foo2恢復調用,執行print后,返回值,min中foo2調動結束彈出棧頂 def foo3(d): print("foo3 called",d) #第七步:foo3完成portin函數調用后返回。 def main(): print("main called") #第二步:main中查找內建函數print壓棧,將常量字符串壓棧,調用函數,彈出棧頂 foo1(100,101) #第三步:main中全局查找函數foo1壓棧,將常量100,101壓棧,調用函數foo1,創建棧幀 foo2(200) #第五步:main中全局查找foo2函數壓棧,將常量200壓棧,調用foo2,創建棧幀。 print("main ending") #第六步:main繼續執行print函數調用,彈出棧頂,main函數返回 main() #第一步:main函數調用main()函數 #返回結果: main called foo1 called 100 101 foo3 called 200 foo2 called 200 main ending
2.函數的遞歸(Recursion)
(1)函數直接或者間接調用自身就是遞歸
(2)遞歸需要有邊界條件,遞歸前進段,遞歸返回段
(3)遞歸一定要有邊界條件
(4)當邊界條件不滿足的時候,遞歸前進
(5)當邊界條件滿足的時候,遞歸返回
(6)舉例:
def fib(n): return 1 if n < 2 else fib(n-1) + fib(n-2) #第二步:判斷4不小於2走else得到fib(3)+fib(2),當前要返回的值是2 #第三步:fib(3)調用函數把3傳進去,判斷3不小於2走else得到fib(2)+fib(1),當前要返回的值是3 #第四步:fib(2)調用函數把2傳進去,判斷2不小於2走else得到fib(1),當前要返回的值是4 #第五步:fib(1)調用函數把1傳進去,判斷1小於2是邊界return返回,當前要返回的值是5 print(fib(4)) #第一步:調用fib函數把4傳進去 #返回結果 5
3.遞歸要求
(1)遞歸一定要有退出條件,遞歸調用一定要執行到這個退出條件。沒有退出條件的遞歸調用,就是無限調用。
(2)遞歸調用的深度不宜過深:python對遞歸調用的深度做了限制,以保護解釋器,超過遞歸深度限制,拋出RecursionError:maxinum recursion depth exceeded超出最大深度sys.getrecursionlimit()
4.遞歸的性能
(1)未優化遞歸實現斐波那契數列(循環寫法)
import datetime n = 35 start = datetime.datetime.now() def fib(n): return 1 if n < 2 else fib(n - 1) + fib(n - 2) for i in range(n): print(fib(i),end=' ') delta = (datetime.datetime.now() - start).total_seconds() print() print('執行時間:',delta) #返回結果: 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578 5702887 9227465 執行時間: 8.91451
總結:
1)循環稍微復雜一些,但是只要不是死循環,可以多次迭代直至算出結果
2)fib函數代碼極簡易懂,但是只能獲取到最外層的函數調用,內部遞歸結果都是中間結果,而且給定一個n都要進行2n次遞歸,深度越深,效率越低,為了獲取斐波那契數列需要外面在套一個n次的循環,效率就更低了
3)遞歸還有深度限制,如果遞歸復雜,函數返回壓棧,棧內存內褲就溢出了
(2)優化遞歸實現斐波那契數列(上一次的計算結果直接作為函數的實參)
pre = 0 cur = 1 #print(pre,cur) def fib(n,pre=0,cur=1): pre,cur = cur,pre + cur print(cur,end=' ') if n == 2: return #return none fib(n-1,pre,cur) #第二步:函數接收參數fib(n=5,pre=0,cur=1),pre(1),cur(1) = cur(1)給pre,(pre + cur)(1)給cur,當前cur是1打印1,if判斷5不等於2,當前fib(5-1,pre(1),cur(1))繼續遞歸 #第三步:函數接收參數fib(n=4,pre=1,cur=1),pre(1),cur(2) = cur(1)給pre,(pre + cur)(2)給cur,當前cur是2打印2,if判斷4不等於2,當前fib(4-1,pre(1),cur(2))繼續遞歸 #第四步:函數接收參數fib(n=3,pre=1,cur=2),pre(2),cur(3) = cur(2)給pre,(pre + cur)(3)給cur,當前cur是3打印3,if判斷3不等於2,當前fib(3-1,pre(2),cur(3))繼續遞歸 #第五步:函數接收參數fib(n=2,pre=2,cur=3),pre(3),cur(5) = cur(3)給pre,(pre + cur)(5)給cur,當前cur是1打印1,if判斷2等於2執行return none跳出遞歸 fib(5) #第一步:調用函數把5傳進去 #返回結果: 1 2 3 5
總結:
1)fib函數和循環的思想類似
2)參數n是邊界條件,用n來計數
3)上一次的計算結果直接作為函數的實參
4)效率很高
5)和循環比較,性能相近。所以並不是說遞歸一定效率低下。但是遞歸有深度限制
5.間接遞歸
間接遞歸,是通過別的函數調用了函數自身,但是,如果構成了函數遞歸調用是非常危險的,但是往往這種清空在代碼復雜的情況下,還是可以發生這種調用。要用代碼的規范來避免這種遞歸調用的發生
def foo1(): foo2() def foo2(): foo1() foo1()
6.遞歸總結
(1)遞歸是一種很自然的表達,符合邏輯思維
(2)遞歸相對運行效率低,每一次調用函數都要開辟棧幀
(3)遞歸有深度限制,如果遞歸層次太深,函數反復壓棧,棧內存很快就溢出了
(4)如果是有限次數的遞歸,可以使用遞歸調用,或者使用循環代替,循環代替稍微復雜一些,但是只要不是死循環,可以多次迭代直至算出結果
(5)絕大多數遞歸,都可以使用循環實現
(6)即使遞歸代碼很簡潔,但是能不用則不用遞歸
7.遞歸應用
#!/usr/bin/python # -*- coding: utf-8 -* import time person_list=['wang','shi','yao'] #定義人名列表['wang','shi','yao'] def ask_way(person_list): #定義函數把人這個列表傳進去 print('-'*30) if len(person_list) == 0: #如果person_lis不在['wang','shi','yao']這些里代表沒人知道 return '沒人知道' person=person_list.pop(0) #把每次列表的名字一次彈出一個賦值給person if person == 'yao': #如果人名等於yao執行return 返回"我知道,路就在這里" return '%s說:我知道,路就在這里' %person print('xix問:[%s],路在那里?' %person) print('%s回答道:我不知道,你等着,我幫你問問%s...' %(person,person_list)) time.sleep(2) res=ask_way(person_list) #遞歸着問就要在函數里面調用自己(把問的結果交給res) return res res=ask_way(person_list) print(res) #輸出結果: ------------------------------ xix問:[wang],路在那里? wang回答道:我不知道,你等着,我幫你問問['shi', 'yao']... ------------------------------ xix問:[shi],路在那里? shi回答道:我不知道,你等着,我幫你問問['yao']... ------------------------------ yao說:我知道,路就在這里
第七部分:內建函數
1.標識id:返回對象的唯一標識,CPython返回內存地址
2.哈希hash():可hash的數據類型即不可變數據類型,不可hash的數據類型即可變數據類型
(1)特性:
<1>不管傳入參數有多長最終結果長度固定
<2>不能根據最終hash的最終結果反推出來
<3>只要變量不變,得到的hash值結果都一樣
hash('xixi') #字符串 #返回:485502670088932892 hash(str(sorted({'1':1}))) #字典 #返回:7666464346782421378
3.類型type():返回對象的數據類型
msg='123' if type(msg) is str: #判斷msg是否是整型 msg=int(msg) #不是轉換成int res=msg+1 print(res) #返回:124
4.類型轉換:float() int() bin() hex() oct() bool() list() tuple() dict() set() complex() bytes() bytearray()
5.輸入input([prompt]):接收用戶輸入,返回一個字符串
6.打印print(*objects,sep='',end='\n',file=sys.stdout,flush=False):打印輸出,默認使用空格分割,換行結尾,輸出到控制台
7.對象長度len(s):返回一個集合類型的元素個數
8.isinstance(obj,class_or_tuple):判斷對象obj是否屬於某種類型或者元祖中列出某個類型
a = 2 isinstance (a,int) #判斷a是否是int類型 #返回:True
9.issubclass(cls,class_or_tuple):判斷類型cls是否是某種類型的子類型或元祖中列出的某個類型的子類
10.絕對值abs(x):x為數值
print (abs(-45)) #返回:45
11.最大值max(),最小值()
功能1:簡單列表比較
l=[1,2,3,-5,100] print(max(l)) print(min(l)) #返回: 100 -5
功能2:比較復雜列表
l=[(5,'e'),(1,'c'),(2,'b'),(3,'d'),] #默認從第一個值開始比較5最大 print(list(max(l))) #返回:[5, 'e']
功能3:比較字典
age_dic={'age1':19,'age4':20,'age3':100,'age2':30} print(max(age_dic)) #默認比較的是字典的key,根據ASCII碼逐步去比較大小 print(max(age_dic.values())) #比較的是字典的value print((max(zip(age_dic.values(),age_dic.keys()))) ) #(zip(age_dic.values(),age_dic.keys())相當於[(19,'age1'),(20,'age4'),(100,'age3') ] #返回: age4 100 [100, 'age3']
功能4:比較復雜的字典
people=[{'name':'xixi','age':1000},{'name':'wang','age':1111},{'name':'shi','age':111},{'name':'yao','age':11},] print(max(people,key=lambda dic:dic['age'])) #for循環people把取出來的值都給lambda表達式,值都是小字典 #返回:{'age': 1111, 'name': 'wang'}
注意:
(1)max和min函數處理的是可迭代對象,相當於for循環取出每個元素進行比較,不通類型直接不能進行比較。
(2)每個元素間進行比較,是從每個元素的第一個位置以此比較,如果第一位置分出大小,后面的都不需要比較,直接得出這倆元素的大小
12.round(x)四舍六入五取偶,round(-0.5)
print(round(3.5)) #返回:4
13.pow(x,y)等價於x**y
print(pow(3,3)) #返回:9
14.range(stop)從0開始到stop-1的可迭代對象;range(start,stop[,step])從start開始到stop-1結束步長為step的可迭代對象
15.divmod(x,y)除數和余數運算結果結合起來(做分頁功能),等價於tuple(x//y,x%y)
divmod(10, 3) #返回:(3, 1)---3總共分了3頁余1頁
16.sum(iterable[,start])對可迭代對象的所有數值元素求和
l=[1,2,3,4] print(sum(l)) #返回:10
17.chr(i)給一個一定范圍的整數返回對應的字符
1)十六進制
print chr(0x30), chr(0x31), chr(0x61) #十六進制 #返回:0 1 a
2)十進制
print chr(48), chr(49), chr(97) #十進制 #返回:0 1 a
18.ord()返回對應的ASCII數值
print(ord('a')) #返回:97
19.str()將對象轉化為字符串
print(str({'a':1})) #返回:"{'a':1}"
20.repr()函數將對象轉化為供解釋器讀取的形式
21.sorted(iterable[,key][,reverse])排序,返回一個新的列表,默認升序,revers是反轉
舉例:默認升序
>>> sorted([3,1,5])
[1, 3, 5]
舉例:加參數
>>> sorted([1,3,5],reverse=True)
[5, 3, 1]
22.翻轉reversed(seq):返回一個翻轉元素的迭代器
舉例:(reversed("13579")生成可迭代對象元素,list生成新列表
>>> list(reversed("13579")) ['9', '7', '5', '3', '1']
23.枚舉enumerate(seq,start=0)
迭代一個序列,返回索引數字和元素構成的二元組,start表示索引開始的數字,默認是0
(1)舉例:
for i in enumerate(range(5)): print(i) #返回:二元組 (0, 0) (1, 1) (2, 2) (3, 3) (4, 4)
(2)舉例:帶參數索引偏移
for i in enumerate(range(5),start=2): print(i) #返回: (2, 0) (3, 1) (4, 2) (5, 3) (6, 4)
(3)舉例:每次循環k,v解構拿到兩個值
for k,v in enumerate(range(5)): print(k,v,end="\t") #返回: 0 0 1 1 2 2 3 3 4 4
24.迭代器和取元素iter(iterable),next(iterator)
iter講一個可迭代對象封裝成一個迭代器
next對一個迭代器去下一個元素,如果全部元素都取過了,再次next會拋出StopIteration異常
舉例:next按順序每次拿一個
>>> it=iter(range(3)) >>> next(it) 0 >>> next(it) 1 >>> next(it) 2 >>> next(it) #報錯 Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
舉例:reversed按順序隔一個取
>>> it = reversed([1,3,5]) >>> next(it) 5 >>> next(it) 3 >>> next(it) 1 >>> next(it) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
25.拉鏈函數zip(*iterables)
像拉鏈一樣,把多個可迭代對象合並在一起,返回一個迭代器,將每次從不同對象中取到的元素
舉例:從第一個迭代對象拿一個0,從第二個迭代對象里拿一個0湊成一對,以此類推生成元祖
>>> list(zip(range(10),range(10)))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9)]
舉例:從第一個迭代對象拿一個0,從第二個迭代對象里拿一個0湊成一對,以此類推生成元祖,以最短的配
>>> list(zip(range(10),range(10),range(5)))
[(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4)]
舉例:從第一個迭代對象拿一個0,從第二個迭代對象里拿一個0湊成一對,以此類推生成元祖,解構成字典
>>> {str(x):y for x,y in zip(range(10),range(10))} {'6': 6, '9': 9, '5': 5, '4': 4, '0': 0, '3': 3, '7': 7, '2': 2, '1': 1, '8': 8}
26.all():把序列所有元素做布爾運算如果都是返回true,否則返回false(元素除了是 0、空、FALSE外都算TRUE)
舉例1:
all(['a', 'b', 'c', 'd']) #列表list,元素都不為空或0 #返回:True
舉例2:
all(['a', 'b', '', 'd']) #列表list,存在一個為空的元素 #返回:False
27.any():把序列所有元素做布爾運算如果都是返回true,如果有一個為True,則返回True,如全是0、空、FALSE則返回FALSE
舉例1:
any(['a', 'b', 'c', 'd']) #列表list,元素都不為空或0 #返回:True
舉例2:
any(['a', 'b', '', 'd']) #列表list,存在一個為空的元素 #返回:True
舉例3:
any([0, '', False]) #列表list,元素全為0,'',false #返回:False
28.bytes():把一個字符串轉換成字節的形式(編碼轉換二進制)
name="你好" print(bytes(name,encoding='utf-8')) #返回: b'\xe4\xbd\xa0\xe5\xa5\xbd'
decode方式解碼:
print(bytes(name,encoding='utf-8').decode('utf-8')) #返回:你好
29.chr():用一個范圍在 range(256)內的(就是0~255)整數作參數,返回一個對應的字符。
30.dir():打印某一個對象下面的各種方法名字
31.eval():
功能1:把字符串里的數據結構提取出來
dic_str1="{'name':'xixi'}" eval(dic_str1) #返回:{'name': 'xixi'}
功能2:把字符串里的數學運算做一遍
x=5 eval( '3 * x' ) #返回:15
32.help():打印方法的相關解釋
33.bin():把10進制轉換成2進制,以字符串形式表示
bin(10) #返回:'0b1010'
34.hex()函數:將10進制整數轉換成16進制,以字符串形式表示
hex(255) #返回:'0xff'
35.oct()函數:將一個整數轉換成8進制字符串
oct(10) #返回:'012'
36.globals()函數:會以字典類型返回當前位置的全部全局變量
a='xixi' print(globals()) #globals函數返回一個全局變量的字典,包括所有導入的變量。 #返回:{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, 'a': 'xixi', '__package__': None}
37.locals()函數:會以字典類型返回當前位置的全部局部變量
def runoob(arg): #第一個局部變量argz z = 1 #第二個局部變量z print (locals()) runoob(2) #返回:{'z': 1, 'arg': 2} #返回一個名字/值對的字典
38.set()函數:創建一個無序不重復元素集
print(set('hello')) #返回:{'l','o','h','e'}
39.slice()函數:實現切片對象,主要用在切片操作函數里的參數傳遞
l='hello' s1=slice(3.5) s2=slice(1,4,2) #取步長 print(l[s1]) print(l[s2]) 返回: lo ell='hello' s1=slice(3.5) s2=slice(1,4,2) #取步長 print(l[s1]) print(l[s2]) #返回: lo el
40.str()函數:將對象轉化為字符串
41.vars()函數:返回對象object的屬性和屬性值的字典對象
def test(): msg='西西西西西' print(vars()) test() #返回:{'msg': '西西西西西'}
42.__import__()函數:用於動態加載類和函數
43.reduce歸納函數:處理一個序列,然后把序列進行合並操作
舉例1:數字列表[1,2,3,100]把所有的值加起來再加上初始值100
(1)匿名函數lambda方式寫法:
num_l=[1,2,3,100] def reduce_test(func,array,init=None): if init is None: res=array.pop(0) else: res=init for num in array: res=func(res,num) return res print(reduce_test(lambda x,y:x+y,num_l,100)) #詳解:res=array.pop(0)先拿到列表的第一個值,初始值設定默認init=None,判斷當init=None沒有初始值,否則:res=init #輸出: 206
(2)reduce函數寫法:
from functools import reduce #導入模塊 num_l=[1,2,3,100] print(reduce(lambda x,y:x+y,num_l,1)) #指定初始值1 print(reduce(lambda x,y:x+y,num_l)) #不指定初始值 詳解:第一個參數函數lambda x,y:x+y,第二個是一個序列num_l,第三個是初始值1 #輸出: 107 106
舉例:計算1到100的和
from functools import reduce print(reduce(lambda x,y:x+y,range(100),100)) #range(100)相當於得到list列表,然后x,y一次賦倆個值做x+y print(reduce(lambda x,y:x+y,range(1,101))) #輸出: 5050 5050