本文將將主要介紹如下內(nèi)容 函數(shù)介紹1.1 函數(shù)的定義 所謂的函數(shù),,其實(shí)就是具有特定功能的一段代碼塊,都可以獨(dú)立的運(yùn)行 ,。 函數(shù)有5部分組成,,分別是定義函數(shù)的關(guān)鍵字,函數(shù)的名字,,圓括號(hào)(存放函數(shù)的參數(shù)),,函數(shù)功能的實(shí)現(xiàn),函數(shù)的返回語(yǔ)句,。
函數(shù)的語(yǔ)法格式: def 函數(shù)名(參數(shù)列表): 函數(shù)體 return 示例:
#帶一個(gè)參數(shù)def show(msg) print(msg)
1.2函數(shù)的調(diào)用 調(diào)用函數(shù),,其實(shí)就是使用函數(shù)。調(diào)用函數(shù)時(shí)直接使用函數(shù)名即可,。 調(diào)用語(yǔ)法: 函數(shù)名(參數(shù)列表) 調(diào)用以上定義的函數(shù)
1.3函數(shù)的返回 函數(shù)的返回用于退出該函數(shù),,函數(shù)返回使用return進(jìn)行表示,return后面可以根具體值,,也可以不跟,。如果不跟任何值代表返回None。 一般return后的值有以下幾種情況:
示例 def show(msg): print(msg) return None #這樣代碼可以忽略,。def add(x,y): z = x +y return z #返回某個(gè)值def add(x,y): return x + y #直接返回參與運(yùn)算后的結(jié)果def calc(x,y): add = x+y sub = x-y return add,sub #返回了兩個(gè)值 1.4 小結(jié) 最后,,我們將上面講的內(nèi)容通過(guò)一張思維導(dǎo)圖來(lái)總結(jié),具體如下 函數(shù)的參數(shù)在調(diào)用函數(shù)時(shí),,經(jīng)常會(huì)用到形式參數(shù)(簡(jiǎn)稱(chēng)“形參”)和實(shí)際參數(shù)(簡(jiǎn)稱(chēng)“實(shí)參”),二者的主要區(qū)別是:
print(add(3,4)) #調(diào)用add函數(shù)時(shí),,實(shí)際傳入的3和4就是實(shí)際參數(shù) ,。 需要注意的是,一個(gè)函數(shù)實(shí)際上可以接受任何類(lèi)型的值,,比如字符串,,整數(shù),浮點(diǎn)數(shù),,列表,,元組,字典等,。 當(dāng)函數(shù)的形式參數(shù)中要傳遞實(shí)際的值時(shí),,也會(huì)分兩種情況,不可變對(duì)象值(值傳遞)傳遞和可變對(duì)象值傳遞(引用傳遞),。 函數(shù)中的不可變對(duì)象值傳遞,,示例:
運(yùn)行后可以看出,無(wú)論函數(shù)中如何作用x的值,,實(shí)際的x值是不會(huì)發(fā)生變化的 ,,傳入sum函數(shù)里的值其實(shí)就是x=10的一份副本 。 函數(shù)中的可變對(duì)象傳遞,,示例 my_lst = ['java', 'c++', 'python','go']def update_lst(lst): lst.insert(1,'ruby') return lstprint('調(diào)用函數(shù)后返回的值:',update_lst(my_lst))print('my_lst的值:',my_lst) 運(yùn)行結(jié)果: 以上結(jié)果可以看出,,通過(guò)函數(shù)作用于my_list列表后,,列表內(nèi)的值也發(fā)生改變了,他們兩同時(shí)指向了一個(gè)列表 ,。 最后,,用個(gè)形象的例子總結(jié)一下,不可變對(duì)象就像是一個(gè)pdf文件,,文件內(nèi)容本身不能改變,,但是可以拷貝,所以在函數(shù)中使用不可變對(duì)象都是使用的是拷貝后的副本,。而可變對(duì)象就像是execl,。execl中的內(nèi)容是可變化的 。但是操作的都是源文件,函數(shù)中操作的可變對(duì)象也是對(duì)源文件里的內(nèi)容進(jìn)行操作 ,。 從參數(shù)的類(lèi)型劃分,,可以將參數(shù)劃分為:位置參數(shù),默認(rèn)參數(shù),,關(guān)鍵字參數(shù),,可變參數(shù)。 2.1 位置參數(shù): 所謂的位置參數(shù),,主要是指輸入函數(shù)內(nèi)的參數(shù)數(shù)量和位置要和定義的形參中的一致,。傳多或傳少都會(huì)報(bào)錯(cuò)。
2.2 默認(rèn)參數(shù) 如果函數(shù)的某個(gè)參數(shù)經(jīng)常會(huì)使用到一個(gè)值,那我們就可以給這個(gè)參數(shù)設(shè)置一個(gè)默認(rèn)值 ,,當(dāng)調(diào)用該函數(shù)時(shí),,該參數(shù)若不傳入值,就會(huì)使用到默認(rèn)值,。設(shè)置的默認(rèn)參數(shù)需放在關(guān)鍵字參數(shù)后 ,。 示例: #默認(rèn)參數(shù)實(shí)例def show_lgg(msg,lgg='python'): info = ('{}{}'.format(msg,lgg)) return infoprint(show_lgg('使用默認(rèn)的開(kāi)發(fā)語(yǔ)言:'))print(show_lgg('使用默認(rèn)的開(kāi)發(fā)語(yǔ)言:','java'))#輸出使用默認(rèn)的開(kāi)發(fā)語(yǔ)言:python使用默認(rèn)的開(kāi)發(fā)語(yǔ)言:java 從以上結(jié)果可以看出,函數(shù)show_lgg中的lgg設(shè)置了默認(rèn)值python,,當(dāng)該參數(shù)沒(méi)有傳值時(shí),,使用的是默認(rèn)的值。若該參數(shù)傳入值后,,使用的就是傳入的值 ,。 那這個(gè)默認(rèn)參數(shù)的用處就是,當(dāng)函數(shù)的參數(shù)值頻繁的使用某一個(gè)值或者優(yōu)先被使用該值時(shí),,都可以將其設(shè)置為默認(rèn)值 ,。比如我們經(jīng)常使用的瀏覽器,那么多的瀏覽器中,,我們最常用的Chrome,,那么就可以將Chrome設(shè)置為默認(rèn)值。不傳入該參數(shù)時(shí)默認(rèn)就會(huì)使用Chrome ,。 使用默認(rèn)參數(shù)時(shí)要注意,,位置參數(shù)需放在默認(rèn)參數(shù)前面,否則python會(huì)報(bào)錯(cuò),。使用它可以簡(jiǎn)化我們的調(diào)用,,增加靈活度。 2.3 關(guān)鍵字參數(shù) 關(guān)鍵字參數(shù)是指?jìng)鬟f給參數(shù)要以key=value形式,key代表函數(shù)中的形參名稱(chēng),,value就是傳遞給函數(shù)的實(shí)際的值,。 使用關(guān)鍵字參數(shù)后,參數(shù)的位置就可以進(jìn)行調(diào)換了 ,。
以上方式都可以正常正常調(diào)用,但是需要注意的是,,當(dāng)關(guān)鍵字參數(shù)和位置參數(shù)混合使用時(shí),,位置參數(shù)必須在前,關(guān)鍵字參數(shù)在后,,否則會(huì)報(bào)錯(cuò),。 2.4 可變參數(shù) 這里的可變化參數(shù)指的參數(shù)的數(shù)量可以發(fā)生變化,比如我可以傳遞3個(gè)參數(shù),,也可以傳遞6個(gè),,甚至更多 ??勺兓瘏?shù)有兩種類(lèi)型,,分別是用來(lái)接收元組或列表形式的可變參數(shù);另外一種是用來(lái)接收字典形式的可變參數(shù) ,。 #列表形式的語(yǔ)法格式:def fun_name(a,b,*args): pass?#代碼實(shí)例def show_info(*args): print(args)show_info() #可變參數(shù)也可以不傳入任何參數(shù)show_info('python') #傳入一個(gè)參數(shù)show_info('python','java') #傳入多個(gè)參數(shù)show_info(*['python','java']) #傳入列表,,注意,列表前需要加*show_info(*('python','java')) #傳入元組,,元組前也需要加*#輸出:()('python',)('python', 'java')('python', 'java')('python', 'java') 在可變參數(shù)的參數(shù)名前需加*代,,這樣就代表該參數(shù)為可變參數(shù)了。同時(shí)也傳入的時(shí)候可以是一個(gè)值,,多個(gè)值,,列表或元組 。 還有一種可變參數(shù)就是接收字典中的元素 ,。在函數(shù)中是以雙星**表示,。此函數(shù)同樣能接收多個(gè)位置參數(shù),但是傳入的形式需要以關(guān)鍵字形式傳遞 ,。
也可以將可變參數(shù)列表和字典形式結(jié)合起來(lái)使用 ,。 def fun_name(*args,**kwargs): #此函數(shù)可以接收任何長(zhǎng)度,,任何位置,任何關(guān)鍵字的參數(shù) ,。 pass 針對(duì)以上四種參數(shù),,進(jìn)行總體說(shuō)明:
2.5 小結(jié) 最后,,我們將上面講的內(nèi)容通過(guò)一張思維導(dǎo)圖來(lái)總結(jié),,具體如下 高級(jí)函數(shù)3.1 匿名函數(shù) 使用關(guān)鍵字lambda的表達(dá)式,,又稱(chēng)為匿名函數(shù),。若函數(shù)可以用一行進(jìn)行實(shí)現(xiàn)的話(huà),那么該函數(shù)就可以使用匿名函數(shù)來(lái)代替,。
匿名函數(shù)除了可以賦值給變量外,,還可以通過(guò)函數(shù)的參數(shù)來(lái)傳遞參數(shù)。 #實(shí)現(xiàn):將函數(shù)的參數(shù)a,b傳遞給匿名函數(shù)def add(a,b): z = lambda :a+b return z 3.2 高階函數(shù)-map,reduce,filter,sorted map函數(shù) map()是python的內(nèi)置函數(shù),。map()函數(shù)接收兩個(gè)或多個(gè)參數(shù),,第一個(gè)參數(shù)接收的是函數(shù),后面的參數(shù)是序列,。
map后面的序列也可以是多個(gè) #語(yǔ)法: map(函數(shù),序列1,序列2,...) #實(shí)例num = map(lambda x,y:x+y,[1,2,3,4,5],[6,7,8,9,10])print(list(num))#輸出:[7, 9, 11, 13, 15]#說(shuō)明: map的第二個(gè),,第三個(gè)參數(shù)都是列表,,結(jié)果就是將這兩個(gè)列表每一個(gè)位置的數(shù)進(jìn)行相加 reduce函數(shù) 接收兩個(gè)參數(shù),,第一個(gè)是函數(shù),第二個(gè)是序列 ,。reduce()函數(shù)會(huì)把序列中的每一個(gè)元素累積進(jìn)行計(jì)算,,如何計(jì)算由前面的函數(shù)來(lái)定。
filter函數(shù) 也是接收兩個(gè)參數(shù),,第一個(gè)是函數(shù),,第二個(gè)是序列,filter()函數(shù)會(huì)把傳入的函數(shù)依次作用于每個(gè)元素,,然后根據(jù)返回值是True還是False決定保留還是丟棄該元素,。 #語(yǔ)法: filter(函數(shù),序列) #實(shí)例:查詢(xún)字典中成績(jī)分大于350分的元素dt = {'grade_one': 237, 'grade_two': 532, 'grade_three': 356}dt1 = dict(filter(lambda x:x[1] > 350,dt.items()))print('查詢(xún)年級(jí)分?jǐn)?shù)大于350分的班級(jí):{}'.format(dt1))#輸出:查詢(xún)年級(jí)分?jǐn)?shù)大于350分的班級(jí):{'grade_two': 532, 'grade_three': 356} sorted函數(shù) sorted函數(shù)對(duì)所有可迭代的對(duì)象進(jìn)行排序
3.3 偏函數(shù) 偏函數(shù)其實(shí)就是functools包中的partial函數(shù),。 在前面我們講到函數(shù)的默認(rèn)值可以減少傳遞參數(shù)的數(shù)量,,但是一旦定義了函數(shù)的默認(rèn)值,如果修改的話(huà),,就得修改這個(gè)函數(shù),,很多情況我們底層的一些函數(shù)都是不建議修改的,這個(gè)時(shí)候可以使用偏函數(shù)來(lái)設(shè)置默認(rèn)值,,而且不同的類(lèi)型可以設(shè)置不同的默認(rèn)值 ,。 #簡(jiǎn)化版計(jì)算器def calc(x,y,op='+'): if op == '+': return x + y if op == '-': return x - y if op == '*': return x * y if op == '/': return x / y return x + y#需求:這時(shí)我們又需要進(jìn)行大量的乘法操作,怎么辦呢,? 如下面的操作calc(2,3,'*')calc(2,4,'*')calc(2,5,'*')...calc(2,n,'*')#注意:這個(gè)時(shí)候不建議修改原函數(shù),,因?yàn)樵瘮?shù)也是綜合考慮使用+最多的。不能這時(shí)用*就修改原函數(shù)為* ,。#問(wèn)題:每次傳入的第三個(gè)值都是一個(gè)值,,比較麻煩。能否把它作為默認(rèn)參數(shù)傳進(jìn)來(lái),,#解決方案:使用偏函數(shù)from functools import partialmult=partial(calc,op='*') #把乘法固定print(mult(2,4)) #輸出:8print(mult(6,4)) #輸出:24#說(shuō)明,,使用偏函數(shù)后,參數(shù)op的默認(rèn)值已經(jīng)給定,,所以后面不需要再傳遞該參數(shù) ,。 3.4 遞歸 遞歸就是函數(shù)內(nèi)部又調(diào)用了自己的函數(shù)就被稱(chēng)為遞歸 。
3.5 閉包和裝飾器 閉包 閉包又稱(chēng)為閉合函數(shù),。簡(jiǎn)單來(lái)說(shuō),,閉包的概念就是在函數(shù)內(nèi)再定義一個(gè)函數(shù),這個(gè)內(nèi)部函數(shù)使用了外部函數(shù)的臨時(shí)變量,,且外部函數(shù)的返回值是內(nèi)部函數(shù)的引用時(shí),,我們稱(chēng)之為閉包。 語(yǔ)法: def outer_func(): #外部函數(shù) temp = null #外部函數(shù)的臨時(shí)變量 def inner_func(): 函數(shù)體 return inner_func #將內(nèi)部函數(shù)作為返回值返回 #實(shí)例import operatordef operating(op): #外部函數(shù)定義具體的操作符 def calc(a,b): #內(nèi)部函數(shù)定義計(jì)算的兩個(gè)變量 oprt = { '+': operator.add(a,b), '-': operator.sub(a,b), '*': operator.mul(a,b), '/': operator.truediv(a,b) } return oprt.get(op) return calc #把內(nèi)函數(shù)的引用當(dāng)做外函數(shù)的變量值返回add = operating('+')print(add(3,4)) #輸出:7 那么,,閉包最主要的用途就是裝飾器 ,。 裝飾器 裝飾器的本質(zhì)其實(shí)就是一個(gè)閉包函數(shù),以下就是一個(gè)最為普通的裝飾器,,
通過(guò)和閉包進(jìn)行相比較,,兩者的寫(xiě)法都是一樣的,其實(shí)裝飾器就是一個(gè)閉包函數(shù) ,。那么除了以上調(diào)用方法外,python在后續(xù)的版本又引入了@語(yǔ)法糖,,同樣是上面的代碼,,可以使用如下方式調(diào)用 。 def info(func): def wrapper(): print('[INFO]: 調(diào)用 {}()'.format(func.__name__)) return func() return wrapper@infodef say(): print('hello!') say()#輸出:[INFO]: 調(diào)用 say()hello! 這樣的話(huà),,就通過(guò)@ 標(biāo)識(shí)符將裝飾器應(yīng)用到函數(shù)上了 ,。其實(shí)通過(guò)以上的調(diào)用,實(shí)際上是執(zhí)行了如下2步操作:
以上是一個(gè)最簡(jiǎn)單的裝飾器,,但有一個(gè)問(wèn)題,如果被裝飾的函數(shù)需要傳入?yún)?shù),,那么這個(gè)裝飾器就不能用了 ,,因?yàn)榉祷氐暮瘮?shù)并不能接受參數(shù) 。 帶參數(shù)的函數(shù)裝飾器 通過(guò)制定裝飾器函數(shù)wrapper接受和原函數(shù)一樣的參數(shù),,就可以參數(shù)了 ,。
以上還是只能接受一個(gè)參數(shù),,但實(shí)際情況下,同一個(gè)裝飾器可用于多個(gè)不同的函數(shù),,每個(gè)函數(shù)所帶的參數(shù)都各不相同,,怎么解決呢 ? 這時(shí)我們就可以用到可變參數(shù)*args和**kwargs了,。通過(guò)這兩個(gè)參數(shù),,裝飾器就可以用于任意函數(shù)了 。 def info(func): def wrapper(*args, **kwargs): # 指定*args和**kwargs,接收任意參數(shù) print('[INFO]: 調(diào)用 {}()'.format(func.__name__)) return func(*args, **kwargs) return wrapper # 返回@infodef say(arc1): print('hello {}!'.format(arc1))@infodef todo(x,y): print(x * y)say('作用于多個(gè)函數(shù)的裝飾器')todo(3,5)#輸出:[INFO]: 調(diào)用 say()hello 作用于多個(gè)函數(shù)的裝飾器![INFO]: 調(diào)用 todo()15 3.6 回調(diào)函數(shù) 簡(jiǎn)單的來(lái)說(shuō),,把一個(gè)函數(shù)作為參數(shù)傳給另一個(gè)函數(shù),,那么這個(gè)函數(shù)就是回調(diào)函數(shù)。這個(gè)被傳入的參數(shù)其實(shí)是函數(shù)指針,,即指向一個(gè)函數(shù)的指針(地址),。
回調(diào)函數(shù)還可以進(jìn)行異步調(diào)用,,即非阻塞調(diào)用,,通常用在多線(xiàn)程或者多進(jìn)程中。 3.7 生成器函數(shù) 生成器函數(shù),,就是說(shuō)定義函數(shù)時(shí),,內(nèi)部帶yield就算生成器函數(shù)。在調(diào)用生成器運(yùn)行的過(guò)程中,,每次遇到 yield 就會(huì)返回 其后的值, 并在下一次執(zhí)行 next() 方法是從當(dāng)前位置繼續(xù)運(yùn)行,。 def scq_func(): for x in range(1,10): yield x * 2s = scq_func()print(s) #輸出:<generator object scq_func at 0x0161B510>print(next(s))print(next(s))print(next(s))print(next(s))#輸出:<generator object scq_func at 0x0161B510>2468 以上函數(shù)在執(zhí)行過(guò)程中,遇到y(tǒng)ield就中斷下次又繼續(xù)執(zhí)行,,直到?jīng)]有yield可執(zhí)行了,,再調(diào)用next就會(huì)報(bào)錯(cuò) 。 那該函數(shù)主要的作用是什么呢 ,? 在數(shù)學(xué)中有很多的計(jì)算都是無(wú)限窮盡的(比如自然數(shù)) ,。我們不可能通過(guò)序列去存放,這時(shí)我們就可以使用生成器按照規(guī)則計(jì)算下出一個(gè)數(shù)據(jù),,可以計(jì)算出很大的數(shù) ,。
3.8 小結(jié) 最后,,我們將上面講的內(nèi)容通過(guò)一張思維導(dǎo)圖來(lái)總結(jié),,具體如下 總結(jié)最后我們將上面的介紹做個(gè)整體的回顧,,整體涉及到了如下內(nèi)容:
|
|