函數的參數

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 參數更好且強制關鍵字參數在一些更高級場合同樣也很有用。

繼續學習