Python 學習的第一個難關(guān) -- 函數(shù),這個地方學會的人覺得沒有啥,沒學過的學的時候迷迷瞪瞪,不用慌,學編程就是這樣,先學過去,在從上帝視角去看,堅持打卡,我一天寫一篇,你可以兩天學一篇。
九、Python 中函數(shù)是基礎部分第一道難關(guān)
9.1 函數(shù)出現(xiàn)的背景
為什么在編程語言中會出現(xiàn)函數(shù)概念,目的有 2 個。
- 在開發(fā)的時候,很多項目都是團隊開發(fā),把代碼功能編寫成一個個的函數(shù),方便維護,每個人也可相對獨立的開發(fā),縮短整體開發(fā)時間
- 代碼編寫成函數(shù)以后,重復的功能只寫一次即可,其它地方可以直接調(diào)用,方便了代碼的復用。
直接寫出這兩個目的還是沒有直觀的感受,要在代碼中感受函數(shù)的用法。
9.2 函數(shù)初接觸
咱從本系列博客一開始就已經(jīng)接觸函數(shù)的概念了,例如第一篇就學習的 print
, 就是一個內(nèi)置函數(shù),相似的還有 len
、add
、sorted
這些,調(diào)用函數(shù)時最大的便捷性就是不用知道函數(shù)內(nèi)部的具體實現(xiàn),就可以用該函數(shù)使用自己想要的效果。
9.2.1 函數(shù)的定義
具體的語法格式如下:
def 函數(shù)名稱(參數(shù)1[,參數(shù)2,參數(shù)3...]): 代碼塊 代碼塊 return 返回值
跟 if
語句,for
語句一樣,函數(shù)定義與使用的時候要注意下代碼縮進。
函數(shù)名稱必須是唯一的,進行聲明的有意義,不要使用 a
當做函數(shù)名,以后很有可能就忘記了這個函數(shù)是做什么用的。
參數(shù)值,非必須,根據(jù)函數(shù)的要求自行設定即可,各個參數(shù)值之間用 ,
分隔。
返回值,非必須,返回多個值使用逗號 ,
分隔即可。
注意第一行末尾的分號
9.2.2 無參數(shù)無返回值的函數(shù)
該內(nèi)容將演示函數(shù)的使用便捷性。
# 創(chuàng)建一個函數(shù)def show(): print("我是一個無參數(shù)無返回值的函數(shù)") print("hello world")show()show()show()show()show()
函數(shù)聲明之后,通過 函數(shù)名()
進行調(diào)用,上面的代碼寫了 5 次 show()
,表示函數(shù)被調(diào)用了 5 次。
如果不通過函數(shù)實現(xiàn)上文效果,需要將函數(shù)內(nèi)部的代碼復制 5 次。
print("我是一個無參數(shù)無返回值的函數(shù)")print("hello world")print("我是一個無參數(shù)無返回值的函數(shù)")print("hello world")print("我是一個無參數(shù)無返回值的函數(shù)")print("hello world")print("我是一個無參數(shù)無返回值的函數(shù)")print("hello world")print("我是一個無參數(shù)無返回值的函數(shù)")print("hello world")
單純的復制代碼還好,如果我現(xiàn)在希望將 hello 修改成 hi ,那不使用函數(shù)需要修改代碼的 5 個位置,而使用函數(shù)只需要修改函數(shù)中的代碼塊一處即可。
9.3 函數(shù)的參數(shù)設計
上文中設計的是一個無參數(shù)的函數(shù),但在實際應用中很少出現(xiàn)一個無參函數(shù),更多的時候是需要給函數(shù)傳遞參數(shù)的。
9.3.1 傳遞一個參數(shù)
函數(shù)內(nèi)有參數(shù),代碼如下:
# 聲明一個帶一個參數(shù)的函數(shù)def show(name): print("傳遞進來的姓名是:", name)show("橡皮擦")show("大橡皮擦")show("小橡皮擦")
小括號里面的 name
即為參數(shù),該參數(shù)能在函數(shù)內(nèi)部代碼塊直接使用。
9.3.2 傳遞多個參數(shù)
多個參數(shù)只需要在函數(shù)聲明時小括號里面多增加幾個參數(shù)即可。
# 聲明一個帶多參數(shù)的函數(shù)def show(name, age): print("傳遞進來的姓名是:", name, " 年齡是:", age)show("橡皮擦", 20)show("大橡皮擦", 21)show("小橡皮擦", 18)
多個參數(shù)一定要注意參數(shù)的位置,前后順序如果錯誤,會導致嚴重 BUG。上述代碼中 橡皮擦
會傳遞給 name
,20
會傳遞給 age
。
9.3.3 關(guān)鍵詞參數(shù)(參數(shù)名稱=值)
該參數(shù)使用的方式是在調(diào)用函數(shù)時,參數(shù)用 參數(shù)名稱=值
這種形式傳遞。其實在上述傳遞一個和多個參數(shù)的時候,也可以應用該方式傳遞參數(shù),例如修改代碼如下。
# 聲明一個帶一個參數(shù)的函數(shù)def show(name): print("傳遞進來的姓名是:", name)show(name="橡皮擦")# 聲明一個帶多參數(shù)的函數(shù)def show1(name, age): print("傳遞進來的姓名是:", name, " 年齡是:", age)show1(name="橡皮擦", age=20)
用這種形式調(diào)用函數(shù),參數(shù)的位置就不在重要了,因為已經(jīng)指定參數(shù)具體值是多少。
9.3.4 參數(shù)默認值
在定義函數(shù)的時候可以給參數(shù)一個默認值,如果調(diào)用該函數(shù)沒有給該參數(shù)賦值,程序會使用默認值而不會報錯。
# 沒有默認值的參數(shù)def show(name): print("傳遞進來的姓名是:", name)show() # 該函數(shù)調(diào)用時會報錯# 有默認值的參數(shù)def show(name="橡皮擦"): print("傳遞進來的姓名是:", name)show() # 該函數(shù)調(diào)用沒有問題,即使沒有傳遞參數(shù)會使用默認值
如果一個參數(shù)有默認值,注意該參數(shù)必須放在函數(shù)參數(shù)位置的最右側(cè),例如下述函數(shù)定義。
def show(a,b,c,name="橡皮擦"): pass
9.4 函數(shù)返回值
函授的返回值屬于非必選項,可以寫可以不寫,不寫的時候也會有返回值,該值為 None。
9.4.1 返回 None
函數(shù)如果沒有寫返回值即 return
,那 Python 會自動在函數(shù)體內(nèi)增加一行代碼 return None
。函數(shù)的返回值可以賦值給一個變量,通過打印該變量,即可知道返回的具體內(nèi)容。
# 沒有返回值的函數(shù)def show(): print("注意下面沒有 return")ret = show()print(ret)
得到的 ret
的值是 None,表示沒有返回值。
如果只寫 return,也會返回 None,注意下述代碼是正確的。
# 沒有返回值的函數(shù)def show(): print("注意下面沒有 return") returnret = show()print(ret)
9.4.2 返回一個值
函數(shù)常見的情況是有返回值的,例如執(zhí)行一段計算代碼之后返回計算結(jié)果。
# 定義一個減法函數(shù)def sub(a, b): c = a - b return c# 參數(shù)為 2 和 1,將結(jié)果進行返回ret = sub(2, 1)print(ret)
9.4.3 返回多個值
使用 return 返回函數(shù)數(shù)據(jù),可以一次性返回多個值,返回的數(shù)據(jù)之間用逗號分隔即可。
# 定義一個減法函數(shù)def sub(a, b): c = a - b d = a + b f = a / b return c, d, f# 參數(shù)為 2 和 1,將結(jié)果進行返回ret = sub(2, 1)print(ret)
返回的結(jié)果是一個元組 (1, 3, 2.0)
。
9.4.4 返回字典與列表
函數(shù)可以返回字符串類型的變量,這個與返回一個值一樣,只是具體數(shù)據(jù)類型的區(qū)別,除了上述提及的內(nèi)容,函數(shù)也可以返回比較復雜的數(shù)據(jù),例如字典或者列表,該內(nèi)容沒有特別說明的,你只需要將字典和列表看成普通的數(shù)據(jù)類型進行返回即可,例如下述代碼。
def sub1(): return [1, 2, 3]def sub2(): return {"name": "橡皮擦", "loc": "CSDN"}
9.5 調(diào)用函數(shù)時參數(shù)是列表
為什么多帶帶將其參數(shù)是列表時拿出來講解,是因為列表這個有點特殊,里面還會引出全局變量與局部變量的一個概念,放心第一遍學習 100%迷糊。如果你有其他編程語言的功底,那另當別論。
具體代碼如下,注意看出現(xiàn)的問題。
names = ["aaa","bbb","ccc"]def change_list(one_names): # 修改傳遞進來的列表索引 0 的位置上為 jjj one_names[0] = "jjj"# 函數(shù)調(diào)用,同時將 name 作為參數(shù)傳遞進函數(shù)內(nèi)部change_list(names)print(names)
最終的輸出結(jié)果是 [jjj, bbb, ccc]
,這個表示啥?表示函數(shù)外面的 names
被函數(shù)給修改了。疑問是所有在函數(shù)外面的變量傳遞到參數(shù)內(nèi)部都會被修改嗎?換個整數(shù)試試。
score = 1def change_list(one_score): one_score = 333# 函數(shù)調(diào)用,同時將 score 作為參數(shù)傳遞進函數(shù)內(nèi)部change_list(score)print(score)
此時 score
雖然在函數(shù)內(nèi)部被修改為了 333,但是在函數(shù)外打印并沒有被修改,還是 1?,F(xiàn)在問題就出現(xiàn)了,Python 并不是一視同仁的,列表變量在函數(shù)內(nèi)被修改影響到了外部變量,而整型變量并沒有受到影響。
這個坑咱先挖下,以后慢慢填,為啥列表在函數(shù)內(nèi)修改,函數(shù)外面也會受到影響,涉及到內(nèi)存地址空間這些更底層的概念了。先學習一下局部變量與全局變量。
9.6 局部變量與全局變量
這個概念非常難理解,是的,如果你理解了在這個階段也是一知半解。
在設計函數(shù)的時候,有時需要控制變量的使用范圍,如果變量的使用范圍在函數(shù)內(nèi)部,那這個變量叫做局部變量,注意是函數(shù)內(nèi)部。如果某個變量的使用范圍在整個程序,這個變量就是全局變量。
上述內(nèi)容只是初次接觸,在函數(shù)部分咱先簡單弄個概念在心里在說。
全局變量在所有函數(shù)都能用
score = 1def change_list(): # 輸出全局變量 score,因為這個變量在函數(shù)外面聲明的,大家都可以用 print(score)change_list()# 在函數(shù)外面也可以使用print(score)
上面的 score
并未在函數(shù)內(nèi)部聲明,但是函數(shù)內(nèi)部也可以訪問到,那函數(shù)外面的變量 score
就是全局變量。
局部變量在函數(shù)外部和其它函數(shù)不能使用
def change_list(): # 局部變量 score,本函數(shù)可以用 score = 1 print(score)change_list()# 局部變量 score,在函數(shù)外面不可以使用print(score)# 其它函數(shù)內(nèi)部也不可以使用def show(): print(score)
如果局部變量和全局變量名稱重復
在程序設計的時候很容易出現(xiàn)重名的情況,這種情況比較尷尬了,初學難度繼續(xù)增加。
score = 5555def change_list(): # 局部變量 score,本函數(shù)可以用 score = 6666 print(score)change_list()# 外面使用的全局變量 scoreprint(score)
執(zhí)行之后發(fā)現(xiàn)在外面使用的是全局變量的值 5555,在函數(shù)內(nèi)部使用的局部變量的值 6666。
有了上面的這些基礎知識點,你應該注意下變量的使用范圍這個概念了,在面向?qū)ο蟮臅r候還將繼續(xù)學習。
9.7 傳遞任意數(shù)量的參數(shù)
9.7.1 一般參數(shù)與任意參數(shù)的組合
在 Python 編寫代碼的過程中,很容易出現(xiàn)一種情況是你不知道有多少個參數(shù),這時函數(shù)定義時參數(shù)就不好設定了,好在 Python 已經(jīng)想到了這個情況。
def show(*keys): print("傳入的參數(shù)可以循環(huán)打印") for key in keys: print(key)show(1,2,3,4,5,6,7)
在函數(shù)定義的時候,參數(shù)位置使用 *參數(shù)名
,然后在函數(shù)體重的代碼塊位置就可以進行循環(huán)打印了,可以捕獲到任意數(shù)量的參數(shù)。
如果又有一般參數(shù),又有不定數(shù)量的參數(shù)怎么辦?好辦,使用下面的格式。
def show(name,age,*keys): print("傳入的參數(shù)可以循環(huán)打印") print(name) print(age) for key in keys: print(key)show("www",18,1,2,3)
希望你現(xiàn)在發(fā)現(xiàn)規(guī)律,函數(shù)調(diào)用的時候先依次去匹配函數(shù)定義的參數(shù),一一對應,都對應完畢,發(fā)現(xiàn)沒有一般參數(shù)了,剩下的都打包給 *keys
就好了。
還要不要寫兩個帶 *
的參數(shù),例如 def show(name,*keys,*keys1)
,這樣就報錯了。
9.7.2 一般參數(shù)與任意數(shù)量的關(guān)鍵詞參數(shù)
參數(shù)里面還有一種情況是需要傳不定數(shù)量的關(guān)鍵詞參數(shù),這又如何設計呢?
def show(**args): print("傳入的參數(shù)可以循環(huán)打印") for key in args.items(): print(key)show(name="橡皮擦", age=18)
這種情況,你把傳遞進去的所有參數(shù)當成一個字典即可,自動聚合成了一個字典類型的數(shù)據(jù)。
如果與一般參數(shù)進行匹配,規(guī)則也非常簡單。
def show(name,**args): print("傳入的參數(shù)可以循環(huán)打印") print(name) for key in args.items(): print(key)show(name="橡皮擦", age=18)
上述代碼先去匹配關(guān)鍵詞參數(shù),匹配成功了就賦值到對應關(guān)鍵詞上,例如上面的 name
變量在函數(shù)調(diào)用時賦值了 橡皮擦
,那它就等于橡皮擦,其余的例如 age
沒有關(guān)鍵詞參數(shù)對應,只好打包給 **args
了。
9.8 函數(shù)以后的擴展
函數(shù)本文只是介紹了 5 成左右的內(nèi)容,在 Python 中函數(shù)還有很多有趣的知識點存在,但是不能一口吃飽,那樣的結(jié)果就是消化不好,而且不符合咱滾雪球?qū)W Python 的設計初衷,就是要滾上幾遍才可以徹底掌握。
延期學習的知識點如下:
- 遞歸函數(shù)
- 匿名函數(shù)
- 高階函數(shù)
還有一個知識點你可以現(xiàn)在擴展,咱學習了各種參數(shù)的形式,你有沒有想過將這些組合在一起呢,例如 def show(name,age,*arg,**args)
在程序中是怎么解析的呢?順序變動可不可以呢?
def show(name, age, sex="男", *arg, **args): print("傳入的參數(shù)可以循環(huán)打印") print(name) for key in args.items(): print(key)show("橡皮擦", 18, "女", like=99)
9.9 這篇博客的總結(jié)
函數(shù),初學階段,這是啥,為什么,不懂唉;學習中期,寫函數(shù)好舒服啊,面向?qū)ο竽抢镉泻瘮?shù)好用;學習后期,快點實現(xiàn)這個功能,啥方法都行,抓緊點,馬上下班了。
沒錯,函數(shù)就處在一個說難很難,轉(zhuǎn)身又很簡單的一個環(huán)節(jié)。
最后一碗毒雞湯
編程需要一個頓悟的時刻,而這個時刻很多人就沒有過。 O(∩_∩)O 哈哈~
????????????????????????????
今天是持續(xù)寫作的第 8 / 100 天。
如果你有想要交流的想法、技術(shù),歡迎在評論區(qū)留言。