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

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

寫(xiě)在前面

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

摘要
本文詳細(xì)介紹了函數(shù)的各種形參類型,包括位置參數(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ù)的形參可以有以下幾種類型:

  • 位置參數(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)的形參類型,其中,位置比名字重要,因?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)稱位置參數(shù))是最重要的參數(shù)類型,在參數(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)用失?。?/p>

# 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í)參類型。因此,可以使用這兩個(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)用父類構(gòu)造函數(shù)時(shí)非常有用!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容