函數的參數
1、預設值參數
有時候,我們自訂的函數中,如果呼叫的時候沒有設定參數,需要給個預設值,這時候就需要用到預設值參數了。
# -*- coding: UTF-8 -*- def print_user_info( name , age , sex = '男' ): # 打印用户信息 print('昵称:{}'.format(name) , end = ' ') print('年龄:{}'.format(age) , end = ' ') print('性别:{}'.format(sex)) return; # 调用 print_user_info 函数 print_user_info( '两点水' , 18 , '女') print_user_info( '三点水' , 25 )
輸出結果:
昵称:两点水 年龄:18 性别:女 昵称:三点水 年龄:25 性别:男
可以看到,當你設定了預設參數的時候,在呼叫函數的時候,不傳該參數,就會使用預設值。但是這裡要注意的一點是:只有在形參表末尾的那些參數可以有預設參數值,也就是說你不能在宣告函數形參的時候,先聲明有預設值的形參而後才宣告沒有預設值的形參。這是因為賦給形參的值是根據位置而賦值的。例如,def func(a, b=1) 是有效的,但是 def func(a=1, b) 是 無效 的。
預設值參數就這樣結束了嗎?還沒有的,細想一下,如果參數中是一個可修改的容器例如一個 lsit (列表)或 dict (字典),那我們用什麼來當預設值呢?我們可以使用 None 作為預設值。就像下面這個例子:
# 如果 b 是一个 list ,可以使用 None 作为默认值 def print_info( a , b = None ): if b is None : b=[] return;
認真看下例子,會不會有這樣的疑問呢?在參數中我們直接 b=[] 不就行了嗎?也就是寫成下面這個樣子:
def print_info( a , b = [] ): return;
對不對呢?運行一下也沒發現錯誤啊,可以這樣寫嗎?這裡需要特別注意的一點:預設參數的值是不可變的對象,例如None、True、False、數字或字串,如果你像上面的那樣操作,當預設值在其他地方被修改後你將會遇到各種麻煩。這些修改會影響到下次呼叫這個函數時的預設值。
範例如下:
# -*- coding: UTF-8 -*- def print_info( a , b = [] ): print(b) return b ; result = print_info(1) result.append('error') print_info(2)
輸出的結果:
[] ['error']
認真觀察,你會發現第二個輸出的值根本不是你想要的,因此切忌不能這樣操作。
還有一點,有時候我就是不要預設值啊,只是想單單判斷預設參數有沒有值傳遞進來,那該怎麼辦?我們可以這樣做:
_no_value =object() def print_info( a , b = _no_value ): if b is _no_value : print('b 没有赋值') return;
這裡的 object 是python中所有類別的基底類別。你可以創建 object 類別的實例,但是這些實例沒什麼實際用處,因為它並沒有任何有用的方法, 也沒有任何實例資料(因為它沒有任何的實例字典,你甚至都不能設定任何屬性值)。你唯一能做的就是測試同一性。也正好利用這個特性,來判斷是否有值輸入。
2、關鍵字參數
在Python 中,可以透過參數名稱來給函數傳遞參數,而不用關心參數列表定義時的順序,這被稱之為關鍵字參數。使用關鍵參數有兩個優點 :
一、由於我們不必擔心參數的順序,使用函數變得更簡單了。
二、假設其他參數都有預設值,我們可以只給我們想要的那些參數賦值
# -*- coding: UTF-8 -*- def print_user_info( name , age , sex = '男' ): # 打印用户信息 print('昵称:{}'.format(name) , end = ' ') print('年龄:{}'.format(age) , end = ' ') print('性别:{}'.format(sex)) return; # 调用 print_user_info 函数 print_user_info( name = '两点水' ,age = 18 , sex = '女') print_user_info( name = '两点水' ,sex = '女', age = 18 )
輸出的值:
昵称:两点水 年龄:18 性别:女 昵称:两点水 年龄:18 性别:女
3、不定長參數
有時我們在設計函數介面的時候,可會需要可變長的參數。也就是說,我們事先無法確定傳入的參數個數。 Python 提供了一種元組的方式來接受沒有直接定義的參數。這種方式在參數前邊加上星號 * 。如果在函數呼叫時沒有指定參數,它就是一個空元組。我們也可以不向函數傳遞未命名的變數。
例如:
# -*- coding: UTF-8 -*- def print_user_info( name , age , sex = '男' , * hobby): # 打印用户信息 print('昵称:{}'.format(name) , end = ' ') print('年龄:{}'.format(age) , end = ' ') print('性别:{}'.format(sex) ,end = ' ' ) print('爱好:{}'.format(hobby)) return; # 调用 print_user_info 函数 print_user_info( '两点水' ,18 , '女', '打篮球','打羽毛球','跑步')
輸出的結果:
昵称:两点水 年龄:18 性别:女 爱好:('打篮球', '打羽毛球', '跑步')
透過輸出的結果可以知道,*hobby是可變參數,而hobby其實就是一個tuple (元祖)
可變長參數也支援關鍵參數,沒有被定義的關鍵參數會被放到一個字典裡。這種方式即是在參數前邊加**,更改上面的示例如下:
# -*- coding: UTF-8 -*- def print_user_info( name , age , sex = '男' , ** hobby ): # 打印用户信息 print('昵称:{}'.format(name) , end = ' ') print('年龄:{}'.format(age) , end = ' ') print('性别:{}'.format(sex) ,end = ' ' ) print('爱好:{}'.format(hobby)) return; # 调用 print_user_info 函数 print_user_info( name = '两点水' , age = 18 , sex = '女', hobby = ('打篮球','打羽毛球','跑步'))
輸出的結果:
昵称:两点水 年龄:18 性别:女 爱好:{'hobby': ('打篮球', '打羽毛球', '跑步')}
透過對比上面的例子和這個例子,可以知道,*hobby是可變參數,且hobby其實就是一個tuple (元祖),**hobby是關鍵字參數,而hobby 就是一個dict (字典)
4、只接受關鍵字參數
關鍵字參數使用起來簡單,不容易參數出錯,那麼有些時候,我們定義的函數希望某些參數強制使用關鍵字參數傳遞,這時候該怎麼辦呢?
將強制關鍵字參數放到某個*參數或單一*後面就能達到這種效果,例如:
# -*- coding: UTF-8 -*- def print_user_info( name , *, age , sex = '男' ): # 打印用户信息 print('昵称:{}'.format(name) , end = ' ') print('年龄:{}'.format(age) , end = ' ') print('性别:{}'.format(sex)) return; # 调用 print_user_info 函数 print_user_info( name = '两点水' ,age = 18 , sex = '女' ) # 这种写法会报错,因为 age ,sex 这两个参数强制使用关键字参数 #print_user_info( '两点水' , 18 , '女' ) print_user_info('两点水',age='22',sex='男')
透過例子可以看,如果age , sex 不適用關鍵字參數是會報錯的。
很多情況下,使用強制關鍵字參數會比使用位置參數表意更清晰,程式也更有可讀性。使用強制關鍵字參數也會比使用 **kw 參數更好且強制關鍵字參數在一些更高級場合同樣也很有用。