Python基礎-函數參數

Python基礎-函數參數

寫在前面

如非特別說明,下文均基于Python3

摘要
本文詳細介紹了函數的各種形參類型,包括位置參數,默認參數值,關鍵字參數,任意參數列表,強制關鍵字參數;也介紹了調用函數時傳遞實參的各種方式,包括位置實參,關鍵字實參以及使用*和**來解包序列和字典。

1. 概述

函數在一定程度上是為了重用而創建的。如果有一段非常優秀的代碼段,實現了網絡資源下載的功能,如果沒有函數,將會在每次需要實現網絡資源下載的地方復制該段代碼。懶惰即美德,將這段代碼抽象為函數,在需要使用的地方調用即可。
函數的使用有以下好處:

  • 增加代碼的可讀性。如在需要下載網絡資源的地方調用函數:download(),可以通過名字讀懂程序的目的;
  • 增加代碼可重用性。相比復制大段代碼,調用函數的可操作性無疑更強;
  • 增加可維護性。如果需要更改下載網絡資源的實現,沒有使用函數的情況下,不得不在每個實用下載功能的地方修改,使用了函數,只需要修改函數即可;
  • 減少犯錯誤的可能性。在復制代碼的過程中,無疑會因為各種原因出現一些差錯,而函數不會。

函數定義非常簡單:

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

以上函數定義的作用是創建函數對象,并且在當前作用域創建名字func,指向函數對象,在可及該作用域范圍內,可以使用名字func調用函數。定義函數時候參數列表中的名字是函數形參,調用函數用的參數是實參。

Python函數的參數十分強大,但相應也為這種強大付出了相對復雜的代價。

函數定義時,函數的形參可以有以下幾種類型:

  • 位置參數 positional parameters,最常用的形參形式,位置比名字重要;
  • 默認參數值 default argument values,param_name = argu_value形式,為形參提供默認值,必須放置在位置參數之后;
  • 任意參數列表 arbitrary argument lists,*args形式,args以元組的形式接收未匹配的位置實參;
  • 關鍵字形參字典 keyword arguments, **kwargs形式,kwargs以字典的形式接收未匹配的關鍵字實參,關鍵字參數需在任意參數列表之后;
  • 強制關鍵字參數 keyword-only arguments,在任意參數列表之后(或者在單獨的*之后),調用是只能使用關鍵字實參。

函數調用時,實參可以由以下方式傳遞:

  • 位置實參按照位置從左到右匹配,位置比名字重要;
  • 關鍵字實參,通過明確形參的名字為其指定實參值。調用時關鍵字實參必須在位置實參之后,且形參列表中要有與之匹配的關鍵字形參;
  • 解包列表/字典,使用*(sequence)從序列中解包位置實參,使用**(dict)的方式從字典中解包關鍵字實參。

當這些不同的形參組合在一起時,構成的函數參數列表將會相當復雜,始終牢記實參形參匹配是位置參數優先。而且,任意參數列表與關鍵字參數組合的形參列表,可以匹配任意方式的函數調用。

2. 位置參數

位置形參是最常見的形參類型,其中,位置比名字重要,因為在實參匹配是是按照位置來的:

# 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))

調用時,如果改變實參位置,意義完全不同:

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

位置形參和位置實參(統稱位置參數)是最重要的參數類型,在參數匹配中它的優先級是最高的。

3. 參數默認值

有其他高級語言(如java)經驗的人知道,有重載函數這一說法,兩個函數的名字相同,其參數列表不同,功能不同。調用者通過指定不同的實參,調用不同形參的重載函數。

但是在Python中沒有重載函數的說法,因為默認參數值得存在,是的調用者在調用同一個函數的時候可以指定不同參數。雖然不支持重載,但是Python以默認參數值的方式實現了重載函數的功能。

指定了默認參數值的形參不能位于位置參數之前,因為實參匹配是位置優先的,這時在前面的指定了默認值的參數會被位置實參覆蓋,導致后面的位置形參無法匹配到實參值而調用失敗:

# 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))
    
# 調用時,可以有多種實參形式
# 指定唯一的強制參數
default_argument_value('Richard')
# 指定其中一個默認參數
default_argument_value('Richard', 22)
# 指定全部參數
default_argument_value('Richard', 22, '002')

4. 任意參數列表

Python的函數相較于其他高級語言強大的地方在于,可以收集多余的未匹配到形參的實參。使用如下格式的形參:*args,收集到尚未匹配到形參的實際參數。

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

# 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))

# 實參1, 2, 3沒有位置形參匹配,被任意參數列表收集
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. 關鍵字參數

在調用函數時,通過位置參數方式調用,每個參數到底匹配哪個形參是不容易發現的,之后查看函數定義才能知道。可以通過指定形參對應的實參值的方式調用,這樣實參形參的匹配更加明了。

還是以位置形參為例:

# 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))

在調用時可以通過關鍵字方式:

# 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')

關鍵字實參必須在位置實參之后,并且可以在形參列表中匹配到形參名字,否則調用失敗:

# 形參中沒有名為id的參數,所以調用失敗
positional_argument(age = 20, name = 'Richard', id = '003')

收集多余關鍵字實參
任意參數列表能夠接收沒有匹配到位置形參的實參,而關鍵字形參字典能夠接受為匹配到關鍵字參數的實參。通過如**kwargs的方式,收集尚未匹配的關鍵字實參,關鍵字參數字典也要在位置參數之后:

# 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'}

另外,關鍵字形參字典需要在任意參數列表之后。

6. 強制關鍵字參數

任意出現在*arg或者*之后的形參都是命名關鍵字參數,意味著它們只能作為關鍵字實參匹配,而非位置實參。

# 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. 序列和字典實參的解包

在函數調用時,使用*sequence將序列解包為位置實參;
使用**dict將字典解包為關鍵字實參。

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解包為位置參數,而**kwargs解包為關鍵字參數,涵蓋了Python中所有可能出現的實參類型。因此,可以使用這兩個組合調用任意形參實行的函數:

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函數中,args是一個元組,kwargs是一個字典,所以可以解包他們組合調用任意形參形式的函數。這一種方式在調用父類構造函數時非常有用!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,637評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,555評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,629評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,976評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,139評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,686評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,411評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,641評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,820評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,362評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,604評論 2 380

推薦閱讀更多精彩內容