二、函數(shù)的參數(shù)
在 Python 中艳悔,兩種類型的參數(shù):在函數(shù)定義時(shí)函數(shù)名后面的括號(hào)中定義的參數(shù)急凰,我們稱之為 形參;在函數(shù)調(diào)用時(shí),函數(shù)名后面的括號(hào)中傳遞的參數(shù)抡锈,我們稱之為 實(shí)參疾忍。形參只有在被調(diào)用時(shí)才分配內(nèi)存單元,在調(diào)用結(jié)束時(shí)床三,即刻釋放所分配的內(nèi)存單元一罩。因此形參只在函數(shù)內(nèi)部有效,形參的作用域只限于函數(shù)內(nèi)撇簿,函數(shù)調(diào)用結(jié)束返回主調(diào)函數(shù)后則不能再使用該形參變量聂渊。
實(shí)參可以是變量名或?qū)ο螅瑹o論實(shí)參是何種類型四瘫,在進(jìn)行函數(shù)調(diào)用時(shí)汉嗽,他們都必須有確定的值,以便把這些值賦值給形參找蜜。
在這里我們明確形參和實(shí)參的概念饼暑,以便于我們下面對(duì)參數(shù)的定義和賦值進(jìn)行更清晰、更深層次的理解洗做。
1弓叛、參數(shù)的傳遞
在 Python 中,函數(shù)參數(shù)(argument竭望,也叫作 parameter)的傳遞是通過自動(dòng)將對(duì)象(實(shí)參)賦值給參數(shù)名(形參)來實(shí)現(xiàn)的,也就是將實(shí)參所指向的對(duì)象(或者其本身就是一個(gè)對(duì)象)的引用賦值給形參裕菠。
函數(shù)參數(shù)的賦值咬清,在實(shí)際中只是 Python 賦值的另一個(gè)實(shí)例而已。因?yàn)橐檬且灾羔樀男问綄?shí)現(xiàn)的奴潘,所有的參數(shù)實(shí)際上都是通過指針進(jìn)行傳遞的旧烧。作為參數(shù)被傳遞的對(duì)象從來不會(huì)進(jìn)行拷貝。如何避免可變參數(shù)的修改
對(duì)可變參數(shù)原處修改的行為不是一個(gè)bug——它只是參數(shù)傳遞在Python中的工作方式。在Python中锭硼,默認(rèn)通過引用(也就是指針)進(jìn)行函數(shù)的參數(shù)傳遞房资,是因?yàn)檫@通常是我們想要的:這意味著不需要?jiǎng)?chuàng)建多個(gè)對(duì)象的拷貝(只用將對(duì)象指向新的變量名)就可以在我們的程序中傳遞很大的對(duì)象,并且能夠按照需要方便的更新這些對(duì)象账忘。
如果不想要函數(shù)內(nèi)部在原處的修改影響傳遞給它的對(duì)象志膀,那么,我們可以簡單地創(chuàng)建一個(gè)明確的可變對(duì)象的拷貝鳖擒。對(duì)于函數(shù)參數(shù)溉浙,我們總是能夠在調(diào)用時(shí)針對(duì)列表進(jìn)行拷貝。這種方法從某種意義上來說有些過于極端:因?yàn)檫@種方法強(qiáng)制函數(shù)寫成絕不改變傳入?yún)?shù)的樣子播赁,這種辦法強(qiáng)制對(duì)函數(shù)比原本應(yīng)該的進(jìn)行了更多的限制颂郎,所以通常意義下應(yīng)該避免出現(xiàn)∪菸或許將來你會(huì)發(fā)現(xiàn)對(duì)于一些調(diào)用來說改變參數(shù)是有用的一件事情乓序。使用這種技術(shù)會(huì)讓函數(shù)失去一種參數(shù)能夠調(diào)用任意列表特定方法的能力,包括不會(huì)在原處改變對(duì)象的那些方法都不再能夠使用坎背。
這里最需要記住的就是替劈,函數(shù)能夠升級(jí)為傳入可變對(duì)象(例如,列表和字典)
的形式得滤,這不會(huì)是一個(gè)問題陨献,并且有時(shí)候這對(duì)于有些用途很有用處。此外懂更,原處修改傳入的可變對(duì)象的函數(shù)眨业,可能是為此而設(shè)計(jì)并有意而為之——修改可能是一個(gè)定義良好的API的一部分,而我們不應(yīng)該通過產(chǎn)生副本來違反改API沮协。
2坛猪、函數(shù)定義時(shí)參數(shù)的類型
這里我們主要介紹的是 Python 的形參。
2.1 標(biāo)準(zhǔn)參數(shù)
就是我們最常用的參數(shù)皂股,在函數(shù)定義時(shí)墅茉,直接以變量名的形式定義。在函數(shù)調(diào)用時(shí),標(biāo)準(zhǔn)參數(shù)必須提供就斤,否則會(huì)報(bào)錯(cuò)悍募。2.2 默認(rèn)參數(shù)
函數(shù)能夠?yàn)閰?shù)定義接收的默認(rèn)值,在函數(shù)定義中洋机, 默認(rèn)參數(shù)以賦值語句 name=value 的形式提供坠宴。在函數(shù)調(diào)用時(shí)如果沒有提供這個(gè)參數(shù), 它就使用這個(gè)默認(rèn)值绷旗。
python 中所有的標(biāo)準(zhǔn)參數(shù)必須出現(xiàn)在任何一個(gè)默認(rèn)參數(shù)之前喜鼓。如果一個(gè)參數(shù)具有默認(rèn)值,所有隨后的參數(shù)直到 “*” 號(hào)也必須具有默認(rèn)值 —— 這個(gè)限制在語法中沒有表達(dá)出來的衔肢。默認(rèn)參數(shù)是在 def 語句運(yùn)行時(shí)評(píng)估并保存的,而不是在這個(gè)函數(shù)調(diào)用時(shí)捍掺。從內(nèi)部來講撼短,Python會(huì)將每一個(gè)默認(rèn)參數(shù)保存成一個(gè)對(duì)象再膳,附加在這個(gè)函數(shù)本身挺勿。
因?yàn)槟J(rèn)參數(shù)是在 def 時(shí)被評(píng)估的,如果必要的話喂柒,它能夠從整個(gè)作用域(函數(shù)定義的作用域)中保存值不瓶,但是因?yàn)槟J(rèn)參數(shù)在調(diào)用之間都保存了一個(gè)對(duì)象,必須對(duì)修改可變的默認(rèn)參數(shù)十分小心灾杰。有些人把這種行為當(dāng)做一種特性蚊丐。因?yàn)榭勺冾愋偷哪J(rèn)參數(shù)在函數(shù)調(diào)用之間保存了他們的狀態(tài),從某種意義上講它們能夠充當(dāng)C語言中的靜態(tài)本地函數(shù)變量的角色艳吠。在一定程度上麦备,它們工作起來就像全局變量,但是它們的變量名對(duì)于函數(shù)來說是本地變量,而且不會(huì)與程序中的其他變量名發(fā)生沖突凛篙。
為什么使用默認(rèn)參數(shù)
默認(rèn)參數(shù)讓程序的健壯性上升到極高的級(jí)別黍匾,因?yàn)樗鼈冄a(bǔ)充了標(biāo)準(zhǔn)位置參數(shù)沒有提供的一些靈活性。當(dāng)少幾個(gè)需要操心的參數(shù)時(shí)候呛梆,生活不再那么復(fù)雜锐涯。利用默認(rèn)參數(shù)你可以為你的API 接口提供一個(gè)常用的默認(rèn)配置,這在一個(gè)程序員剛接觸到一個(gè) API 接口并沒有足夠的知識(shí)來給參數(shù)提供更對(duì)口的值時(shí)顯得尤為有幫助填物。
使用默認(rèn)參數(shù)的概念與在你的電腦上安裝軟件的過程類似纹腌。一個(gè)人會(huì)有多少次選擇默認(rèn)安裝而不是自定義安裝?我可以說可能幾乎都是默認(rèn)安裝滞磺。這既方便升薯,易于操作,又能節(jié)省時(shí)間雁刷。如果你是那些總是選擇自定義安裝的頑固分子覆劈,請記著你只是少數(shù)人之一
另外一個(gè)讓開發(fā)者受益的地方在于,使開發(fā)者更好地控制為顧客開發(fā)的軟件沛励。當(dāng)提供了默認(rèn)值的時(shí)候责语,他們可以精心選擇“最佳“的默認(rèn)值,所以用戶不需要馬上面對(duì)繁瑣的選項(xiàng)目派。隨著時(shí)間流逝坤候,當(dāng)用戶對(duì)系統(tǒng)或者 api 越來越熟悉的時(shí)候,他們最終能自行給出參數(shù)值企蹭,便不再需要使用“學(xué)步車“了白筹。
2.3 可變長參數(shù)(參數(shù)組)
在Python中可以通過定義參數(shù)組,從而讓函數(shù)可以接收任意多額外沒有匹配的基于位置或關(guān)鍵字的參數(shù)谅摄⊥胶樱基本上,你可以將所有參數(shù)放進(jìn)參數(shù)組中送漠,僅僅用這些裝有參數(shù)的容器作為參數(shù)來調(diào)用一個(gè)函數(shù)顽照,而不必顯式地將所有的參數(shù)都放在函數(shù)調(diào)用中。
(1)非關(guān)鍵字參數(shù)(元組)
當(dāng)函數(shù)被調(diào)用的時(shí)候闽寡,調(diào)用者傳遞的位置參數(shù)(實(shí)參)都將按照順序賦給了在函數(shù)聲明中相對(duì)應(yīng)參數(shù)(形參)代兵。剩下的非關(guān)鍵字參數(shù)按順序插入到一個(gè)元組中以便于訪問∫罚可變長的參數(shù)元組必須在位置參數(shù)和默認(rèn)參數(shù)之后植影。
在函數(shù)定義時(shí),使用帶 *
號(hào)的參數(shù)名(通常我們命名為 args)把收集到的不匹配的位置參數(shù)包含在一個(gè)元組中作為參數(shù)傳遞給函數(shù)涎永。
(2)關(guān)鍵字參數(shù)(字典)
在函數(shù)調(diào)用時(shí)思币,當(dāng)有額外的關(guān)鍵字參數(shù)(實(shí)參)沒有與函數(shù)定義的參數(shù)(形參)相匹配時(shí)鹿响,這些關(guān)鍵字參數(shù)會(huì)被放入一個(gè)字典中,字典中鍵為參數(shù)名谷饿,值為相應(yīng)的參數(shù)值抢野。
在函數(shù)定義時(shí),使用帶 **
號(hào)的參數(shù)名(通常我們命名為 kwargs)把接收的關(guān)鍵字參數(shù)包含在一個(gè)字典中作為參數(shù)傳遞給函數(shù)各墨。
2.4 Keyword-only 參數(shù)
Python3.0 把函數(shù)頭部的排序規(guī)則通用化了指孤,并允許我們指定 keyword-only 參數(shù)(形參)——即必須只按照關(guān)鍵字傳遞并且不能由一個(gè)位置參數(shù)(實(shí)參)來填充的參數(shù)(可以理解成必須按照關(guān)鍵字形式賦值的默認(rèn)參數(shù))。如果想要一個(gè)函數(shù)只能按照關(guān)鍵字形式來傳遞配置選項(xiàng)的話贬堵,這是很有用的恃轩。
從語法上將睁宰,keyword-only 參數(shù)編碼為命名的參數(shù)建蹄,出現(xiàn)在參數(shù)(形參)列表中的 *args 之后谬盐。所有這些參數(shù)都必須在調(diào)用中使用關(guān)鍵字語法來傳遞闷畸。
例如,如下代碼中触趴,a可能按照名稱或位置傳遞幻捏,b收集任何額外的位置參數(shù)前普,并且c必須只按照關(guān)鍵字傳遞宏所。
我們也可以在參數(shù)列表中使用一個(gè)字符酥艳,來表示一個(gè)函數(shù)不會(huì)接受一個(gè)變量長度的參數(shù)列表,而是仍然期待跟在后面的所有參數(shù)都作為關(guān)鍵字傳遞爬骤。
排序規(guī)則
keyword-only 參數(shù)必須在一個(gè)單個(gè)星號(hào)后面指定霞玄,而不是兩個(gè)星號(hào)——命名的參數(shù)不能出現(xiàn)在 **kwargs 形式的后面骤铃,并且一個(gè) ** 不能獨(dú)自出現(xiàn)在參數(shù)列表中。為何使用 keyword-only 參數(shù)
簡而言之寇漫,它們使得很容易允許一個(gè)函數(shù)既接收任意多個(gè)要處理的位置參數(shù),也接收作為關(guān)鍵字傳遞的配置選項(xiàng)殉摔。
3州胳、參數(shù)的排列順序
在函數(shù)定義的頭部,參數(shù)必須以此順序出現(xiàn):標(biāo)準(zhǔn)參數(shù)(name)逸月,默認(rèn)參數(shù)(name=value)栓撞,如果有的話,后面是 *args 的形式碗硬,后面跟著任何 name=value 的keyword-only 參數(shù)瓤湘,后面跟著 **kwargs 參數(shù)。
《Python基礎(chǔ)手冊》系列:
Python基礎(chǔ)手冊 1 —— Python語言介紹
Python基礎(chǔ)手冊 2 —— Python 環(huán)境搭建(Linux)
Python基礎(chǔ)手冊 3 —— Python解釋器
Python基礎(chǔ)手冊 4 —— 文本結(jié)構(gòu)
Python基礎(chǔ)手冊 5 —— 標(biāo)識(shí)符和關(guān)鍵字
Python基礎(chǔ)手冊 6 —— 操作符
Python基礎(chǔ)手冊 7 —— 內(nèi)建函數(shù)
Python基礎(chǔ)手冊 8 —— Python對(duì)象
Python基礎(chǔ)手冊 9 —— 數(shù)字類型
Python基礎(chǔ)手冊10 —— 序列(字符串)
Python基礎(chǔ)手冊11 —— 序列(元組&列表)
Python基礎(chǔ)手冊12 —— 序列(類型操作)
Python基礎(chǔ)手冊13 —— 映射(字典)
Python基礎(chǔ)手冊14 —— 集合
Python基礎(chǔ)手冊15 —— 解析
Python基礎(chǔ)手冊16 —— 文件
Python基礎(chǔ)手冊17 —— 簡單語句
Python基礎(chǔ)手冊18 —— 復(fù)合語句(流程控制語句)
Python基礎(chǔ)手冊19 —— 迭代器
Python基礎(chǔ)手冊20 —— 生成器
Python基礎(chǔ)手冊21 —— 函數(shù)的定義
Python基礎(chǔ)手冊22 —— 函數(shù)的參數(shù)
Python基礎(chǔ)手冊23 —— 函數(shù)的調(diào)用
Python基礎(chǔ)手冊24 —— 函數(shù)中變量的作用域
Python基礎(chǔ)手冊25 —— 裝飾器
Python基礎(chǔ)手冊26 —— 錯(cuò)誤 & 異常
Python基礎(chǔ)手冊27 —— 模塊
Python基礎(chǔ)手冊28 —— 模塊的高級(jí)概念
Python基礎(chǔ)手冊29 —— 包