Python基礎(chǔ)-函數(shù)參數(shù)

Python基礎(chǔ)-函數(shù)參數(shù)

寫(xiě)在前面

如非特別說(shuō)明灾常,下文均基于Python3

摘要
本文詳細(xì)介紹了函數(shù)的各種形參類(lèi)型俺叭,包括位置參數(shù)舌仍,默認(rèn)參數(shù)值妒貌,關(guān)鍵字參數(shù),任意參數(shù)列表铸豁,強(qiáng)制關(guān)鍵字參數(shù)灌曙;也介紹了調(diào)用函數(shù)時(shí)傳遞實(shí)參的各種方式,包括位置實(shí)參节芥,關(guān)鍵字實(shí)參以及使用*和**來(lái)解包序列和字典在刺。

1. 概述

函數(shù)在一定程度上是為了重用而創(chuàng)建的逆害。如果有一段非常優(yōu)秀的代碼段,實(shí)現(xiàn)了網(wǎng)絡(luò)資源下載的功能蚣驼,如果沒(méi)有函數(shù)魄幕,將會(huì)在每次需要實(shí)現(xiàn)網(wǎng)絡(luò)資源下載的地方復(fù)制該段代碼。懶惰即美德颖杏,將這段代碼抽象為函數(shù)纯陨,在需要使用的地方調(diào)用即可。
函數(shù)的使用有以下好處:

  • 增加代碼的可讀性输玷。如在需要下載網(wǎng)絡(luò)資源的地方調(diào)用函數(shù):download()队丝,可以通過(guò)名字讀懂程序的目的;
  • 增加代碼可重用性欲鹏。相比復(fù)制大段代碼机久,調(diào)用函數(shù)的可操作性無(wú)疑更強(qiáng);
  • 增加可維護(hù)性赔嚎。如果需要更改下載網(wǎng)絡(luò)資源的實(shí)現(xiàn)膘盖,沒(méi)有使用函數(shù)的情況下,不得不在每個(gè)實(shí)用下載功能的地方修改尤误,使用了函數(shù)侠畔,只需要修改函數(shù)即可;
  • 減少犯錯(cuò)誤的可能性损晤。在復(fù)制代碼的過(guò)程中软棺,無(wú)疑會(huì)因?yàn)楦鞣N原因出現(xiàn)一些差錯(cuò),而函數(shù)不會(huì)尤勋。

函數(shù)定義非常簡(jiǎn)單:

def func([formal_parameter1, ... formal_parameter1]):
    statement

以上函數(shù)定義的作用是創(chuàng)建函數(shù)對(duì)象喘落,并且在當(dāng)前作用域創(chuàng)建名字func,指向函數(shù)對(duì)象最冰,在可及該作用域范圍內(nèi)瘦棋,可以使用名字func調(diào)用函數(shù)。定義函數(shù)時(shí)候參數(shù)列表中的名字是函數(shù)形參暖哨,調(diào)用函數(shù)用的參數(shù)是實(shí)參赌朋。

Python函數(shù)的參數(shù)十分強(qiáng)大,但相應(yīng)也為這種強(qiáng)大付出了相對(duì)復(fù)雜的代價(jià)篇裁。

函數(shù)定義時(shí)沛慢,函數(shù)的形參可以有以下幾種類(lèi)型:

  • 位置參數(shù) positional parameters,最常用的形參形式达布,位置比名字重要团甲;
  • 默認(rèn)參數(shù)值 default argument values,param_name = argu_value形式往枣,為形參提供默認(rèn)值伐庭,必須放置在位置參數(shù)之后;
  • 任意參數(shù)列表 arbitrary argument lists分冈,*args形式圾另,args以元組的形式接收未匹配的位置實(shí)參;
  • 關(guān)鍵字形參字典 keyword arguments雕沉, **kwargs形式集乔,kwargs以字典的形式接收未匹配的關(guān)鍵字實(shí)參,關(guān)鍵字參數(shù)需在任意參數(shù)列表之后坡椒;
  • 強(qiáng)制關(guān)鍵字參數(shù) keyword-only arguments扰路,在任意參數(shù)列表之后(或者在單獨(dú)的*之后),調(diào)用是只能使用關(guān)鍵字實(shí)參倔叼。

函數(shù)調(diào)用時(shí)汗唱,實(shí)參可以由以下方式傳遞:

  • 位置實(shí)參按照位置從左到右匹配,位置比名字重要丈攒;
  • 關(guān)鍵字實(shí)參哩罪,通過(guò)明確形參的名字為其指定實(shí)參值。調(diào)用時(shí)關(guān)鍵字實(shí)參必須在位置實(shí)參之后巡验,且形參列表中要有與之匹配的關(guān)鍵字形參际插;
  • 解包列表/字典,使用*(sequence)從序列中解包位置實(shí)參显设,使用**(dict)的方式從字典中解包關(guān)鍵字實(shí)參框弛。

當(dāng)這些不同的形參組合在一起時(shí),構(gòu)成的函數(shù)參數(shù)列表將會(huì)相當(dāng)復(fù)雜捕捂,始終牢記實(shí)參形參匹配是位置參數(shù)優(yōu)先瑟枫。而且,任意參數(shù)列表與關(guān)鍵字參數(shù)組合的形參列表绞蹦,可以匹配任意方式的函數(shù)調(diào)用力奋。

2. 位置參數(shù)

位置形參是最常見(jiàn)的形參類(lèi)型,其中幽七,位置比名字重要景殷,因?yàn)樵趯?shí)參匹配是是按照位置來(lái)的:

# positional argument, name is not important, but order matters
def positional_argument(name, age):
    print('name->type:%s, value:%s' % (type(name), name))
    print('age->type:%s, value:%s' % (type(age), age))

調(diào)用時(shí),如果改變實(shí)參位置澡屡,意義完全不同:

positional_argument('Richard', 20)
positional_argument(20, 'Richard')

位置形參和位置實(shí)參(統(tǒng)稱(chēng)位置參數(shù))是最重要的參數(shù)類(lèi)型猿挚,在參數(shù)匹配中它的優(yōu)先級(jí)是最高的。

3. 參數(shù)默認(rèn)值

有其他高級(jí)語(yǔ)言(如java)經(jīng)驗(yàn)的人知道驶鹉,有重載函數(shù)這一說(shuō)法绩蜻,兩個(gè)函數(shù)的名字相同,其參數(shù)列表不同室埋,功能不同办绝。調(diào)用者通過(guò)指定不同的實(shí)參伊约,調(diào)用不同形參的重載函數(shù)。

但是在Python中沒(méi)有重載函數(shù)的說(shuō)法孕蝉,因?yàn)槟J(rèn)參數(shù)值得存在屡律,是的調(diào)用者在調(diào)用同一個(gè)函數(shù)的時(shí)候可以指定不同參數(shù)。雖然不支持重載降淮,但是Python以默認(rèn)參數(shù)值的方式實(shí)現(xiàn)了重載函數(shù)的功能超埋。

指定了默認(rèn)參數(shù)值的形參不能位于位置參數(shù)之前,因?yàn)閷?shí)參匹配是位置優(yōu)先的佳鳖,這時(shí)在前面的指定了默認(rèn)值的參數(shù)會(huì)被位置實(shí)參覆蓋霍殴,導(dǎo)致后面的位置形參無(wú)法匹配到實(shí)參值而調(diào)用失敗:

# default argument values, non-default argument cann't follow default argument
def default_argument_value(name, age = 20, id = '0001'):
    print('name->type:%s, value:%s' % (type(name), name))
    print('age->type:%s, value:%s' % (type(age), age))
    print('id->type:%s, value:%s' % (type(id), id))
    
# 調(diào)用時(shí)系吩,可以有多種實(shí)參形式
# 指定唯一的強(qiáng)制參數(shù)
default_argument_value('Richard')
# 指定其中一個(gè)默認(rèn)參數(shù)
default_argument_value('Richard', 22)
# 指定全部參數(shù)
default_argument_value('Richard', 22, '002')

4. 任意參數(shù)列表

Python的函數(shù)相較于其他高級(jí)語(yǔ)言強(qiáng)大的地方在于来庭,可以收集多余的未匹配到形參的實(shí)參。使用如下格式的形參:*args穿挨,收集到尚未匹配到形參的實(shí)際參數(shù)巾腕。

接收的額外位置實(shí)參以元組的形式存儲(chǔ),且任意參數(shù)列表需要在位置參數(shù)之后:

# Arbitrary Argument Lists
# It receives a tuple containing the positional arguments beyond the formal parameter list. (*name must occur before **name.) 
# be last in the list of formal parameters, because they scoop up all remaining input arguments that are passed to the function

def arbitrary_arguments_list(name, age, *args):
    print('name->type:%s, value:%s' % (type(name), name))
    print('age->type:%s, value:%s' % (type(age), age))
    print('args->type:%s, value:%s' % (type(args), args))

# 實(shí)參1, 2, 3沒(méi)有位置形參匹配絮蒿,被任意參數(shù)列表收集
arbitrary_arguments_list('Richard', 20, 1, 2, 3)

output:

name->type:<class 'str'>, value:Richard
age->type:<class 'int'>, value:20
args->type:<class 'tuple'>, value:(1, 2, 3)

5. 關(guān)鍵字參數(shù)

在調(diào)用函數(shù)時(shí)尊搬,通過(guò)位置參數(shù)方式調(diào)用,每個(gè)參數(shù)到底匹配哪個(gè)形參是不容易發(fā)現(xiàn)的土涝,之后查看函數(shù)定義才能知道佛寿。可以通過(guò)指定形參對(duì)應(yīng)的實(shí)參值的方式調(diào)用但壮,這樣實(shí)參形參的匹配更加明了冀泻。

還是以位置形參為例:

# positional argument, name is not important, but order matters
def positional_argument(name, age):
    print('name->type:%s, value:%s' % (type(name), name))
    print('age->type:%s, value:%s' % (type(age), age))

在調(diào)用時(shí)可以通過(guò)關(guān)鍵字方式:

# keyword arguments. 
# In a function call, keyword arguments must follow positional arguments. 
# All the keyword arguments passed must match one of the arguments accepted by the function, and their order is not important.
positional_argument(age = 20, name = 'Richard')

關(guān)鍵字實(shí)參必須在位置實(shí)參之后,并且可以在形參列表中匹配到形參名字蜡饵,否則調(diào)用失數妗:

# 形參中沒(méi)有名為id的參數(shù),所以調(diào)用失敗
positional_argument(age = 20, name = 'Richard', id = '003')

收集多余關(guān)鍵字實(shí)參
任意參數(shù)列表能夠接收沒(méi)有匹配到位置形參的實(shí)參溯祸,而關(guān)鍵字形參字典能夠接受為匹配到關(guān)鍵字參數(shù)的實(shí)參肢专。通過(guò)如**kwargs的方式,收集尚未匹配的關(guān)鍵字實(shí)參焦辅,關(guān)鍵字參數(shù)字典也要在位置參數(shù)之后:

# keyword arguments dict **kwargs.
# It receives a dictionary containing all keyword arguments except for those corresponding to a formal parameter.
def keyword_argument_dict(name, age, **kwargs):
    print('name->type:%s, value:%s' % (type(name), name))
    print('age->type:%s, value:%s' % (type(age), age))
    print('kwargs->type:%s, value:%s' % (type(kwargs), kwargs))
keyword_argument_dict(name = 'Richard', age = 20, id = '0001', type = 'it')

output:

name->type:<class 'str'>, value:Richard
age->type:<class 'int'>, value:20
kwargs->type:<class 'dict'>, value:{'id': '0001', 'type': 'it'}

另外博杖,關(guān)鍵字形參字典需要在任意參數(shù)列表之后。

6. 強(qiáng)制關(guān)鍵字參數(shù)

任意出現(xiàn)在*arg或者*之后的形參都是命名關(guān)鍵字參數(shù)筷登,意味著它們只能作為關(guān)鍵字實(shí)參匹配剃根,而非位置實(shí)參。

# Keyword only argument.
# Any formal parameters which occur after the *args parameter are ‘keyword-only’ arguments,
# meaning that they can only be used as keywords rather than positional arguments.
def keyword_only_argument(name, *, age, id):
    print('name->type:%s, value:%s' % (type(name), name))
    print('age->type:%s, value:%s' % (type(age), age))
    print('id->type:%s, value:%s' % (type(id), id))

keyword_only_argument('Richard', age = 20, id = '001')

output:

name->type:<class 'str'>, value:Richard
age->type:<class 'int'>, value:20
id->type:<class 'str'>, value:001

7. 序列和字典實(shí)參的解包

在函數(shù)調(diào)用時(shí)前方,使用*sequence將序列解包為位置實(shí)參狈醉;
使用**dict將字典解包為關(guān)鍵字實(shí)參廉油。

def mix_param(name, *args, **kwargs):
    print('name->type:%s, value:%s' % (type(name), name))
    print('args->type:%s, value:%s' % (type(args), args))
    print('kwargs->type:%s, value:%s' % (type(kwargs), kwargs))

mix_param('Richard', *(1, 2, 3), **{'age':20, 'id':'001'})

output:

name->type:<class 'str'>, value:Richard
args->type:<class 'tuple'>, value:(1, 2, 3)
kwargs->type:<class 'dict'>, value:{'age': 20, 'id': '001'}

注意到*args解包為位置參數(shù),而**kwargs解包為關(guān)鍵字參數(shù)苗傅,涵蓋了Python中所有可能出現(xiàn)的實(shí)參類(lèi)型娱两。因此,可以使用這兩個(gè)組合調(diào)用任意形參實(shí)行的函數(shù):

def foo(x, y, z, m = 0, n = 0):
    print(x, y, z, m, n)

def call_foo(*args, **kwargs):
    print('Call foo!')
    foo(*args, **kwargs)

注意到call_foo函數(shù)中金吗,args是一個(gè)元組,kwargs是一個(gè)字典趣竣,所以可以解包他們組合調(diào)用任意形參形式的函數(shù)摇庙。這一種方式在調(diào)用父類(lèi)構(gòu)造函數(shù)時(shí)非常有用!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末遥缕,一起剝皮案震驚了整個(gè)濱河市卫袒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌单匣,老刑警劉巖夕凝,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異户秤,居然都是意外死亡码秉,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)鸡号,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)转砖,“玉大人,你說(shuō)我怎么就攤上這事鲸伴「幔” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵汞窗,是天一觀(guān)的道長(zhǎng)姓赤。 經(jīng)常有香客問(wèn)我,道長(zhǎng)仲吏,這世上最難降的妖魔是什么不铆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮裹唆,結(jié)果婚禮上狂男,老公的妹妹穿的比我還像新娘。我一直安慰自己品腹,他們只是感情好岖食,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著舞吭,像睡著了一般泡垃。 火紅的嫁衣襯著肌膚如雪析珊。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,598評(píng)論 1 305
  • 那天蔑穴,我揣著相機(jī)與錄音忠寻,去河邊找鬼。 笑死存和,一個(gè)胖子當(dāng)著我的面吹牛奕剃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播捐腿,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼纵朋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了茄袖?” 一聲冷哼從身側(cè)響起操软,我...
    開(kāi)封第一講書(shū)人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宪祥,沒(méi)想到半個(gè)月后聂薪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蝗羊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年藏澳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耀找。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡笆载,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涯呻,到底是詐尸還是另有隱情凉驻,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布复罐,位于F島的核電站涝登,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏效诅。R本人自食惡果不足惜胀滚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乱投。 院中可真熱鬧咽笼,春花似錦、人聲如沸戚炫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至施掏,卻和暖如春钮惠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背七芭。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工素挽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人狸驳。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓预明,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親耙箍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子撰糠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容