Python可變參數函數用法詳解
來自:http://c.biancheng.net/view/2257.html
很多程式設計語言都允許定義個數可變的參數,這樣可以在調用函數時傳入任意多個參數。Python 當然也不例外,Python 允許在形參前面添加一個星号(*),這樣就意味着該參數可接收多個參數值,多個參數值被當成元組傳入。
下面程式定義了一個形參個數可變的函數:
- # 定義了支援參數收集的函數
- def test(a, *books) :
- print(books)
- # books被當成元組處理
- for b in books :
- print(b)
- # 輸出整數變量a的值
- print(a)
- # 調用test()函數
- test(5 , "C語言中文網" , "Python教程")
運作上面程式,将看到如下運作結果:
('C語言中文網', 'Python教程')
C語言中文網
Python教程
5
從上面的運作結果可以看出,當調用 test() 函數時,books 參數可以傳入多個字元串作為參數值。從 test() 的函數體代碼來看,參數收集的本質就是一個元組: Python 會将傳給 books 參數的多個值收內建一個元組。
Python 允許個數可變的形參可以處于形參清單的任意位置(不要求是形參清單的最後一個參數),但 Python 要求一個函數最多隻能帶一個支援“普通”參數收集的形參。例如如下程式:
- def test(*books ,num) :
- print(num)
- test("C語言中文網", "Python教程", num = 20)
正如從上面程式中所看到的,test() 函數的第一個參數就是個數可變的形參,由于該參數可接收個數不等的參數值,是以如果需要給後面的參數傳入參數值,則必須使用關鍵字參數,否則程式會把所傳入的多個值都當成是傳給 books 參數的。
Python 還可以收集關鍵字參數,此時 Python 會将這種關鍵字參數收內建字典。為了讓 Python 能收集關鍵字參數,需要在參數前面添加兩個星号。在這種情況下,一個函數可同時包含一個支援“普通”參數收集的參數和一個支援關鍵字參數收集的參數。例如如下代碼:
- def test(x, y, z=3, *books, **scores) :
- print(x, y, z)
- print(scores)
- test(1, 2, 3, "C語言中文網" , "Python教程", 國文=89, 數學=94)
上面程式在調用 test() 函數時,前面的 1、2、3 将會傳給普通參數 x、y、z;接下來的兩個字元串将會由 books 參數收內建元組;最後的兩個關鍵字參數将會被收內建字典。運作上面代碼,會看到如下輸出結果:
1 2 3
{'國文': 89, '數學': 94}
對于以上面方式定義的 test() 函數,參數 z 的預設值幾乎不能發揮作用。比如按如下方式調用 test() 函數:
test(1, 2, "C語言中文網" , "Python教程", 國文=89, 數學=94)
上面代碼在調用 test() 函數時,前面的 1、2、"C語言中文網" 将會傳遞給普通參數 x、y、z;接下來的一個字元串将會由 books 參數收內建元組;最後的兩個關鍵字參數将會被收內建字典。運作上面代碼,會看到如下輸出結果:
1 2 C語言中文網
('Python教程',)
如果希望讓 z 參數的預設值發揮作用,則需要隻傳入兩個位置參數。例如如下調用代碼:
test(1, 2, 國文=89, 數學=94)
上面代碼在調用 test() 函數時,前面的 1、2 将會傳給普通參數 x、y,此時 z 參數将使用預設的參數值 3,books 參數将是一個空元組;接下來的兩個關鍵字參數将會被收內建字典。運作上面代碼,會看到如下輸出結果:
()
逆向參數收集
所謂逆向參數收集,指的是在程式己有清單、元組、字典等對象的前提下,把它們的元素“拆開”後傳給函數的參數。
逆向參數收集需要在傳入的清單、元組參數之前添加一個星号,在字典參數之前添加兩個星号。例如如下代碼:
- def test(name, message):
- print("使用者是: ", name)
- print("歡迎消息: ", message)
- my_list = ['孫悟空', '歡迎來C語言中文網']
- test(*my_list)
程式中定義了一個需要兩個參數的函數,而 my_list 清單包含兩個元素,為了讓程式将 my_list 清單的兩個元素傳給 test() 函數,程式在傳入的 my_list 參數之前添加了一個星号。
實際上,即使是支援收集的參數,如果程式需要将一個元組傳給該參數,那麼同樣需要使用逆向收集。例如如下代碼:
- def foo(name, *nums):
- print("name參數: ", name)
- print("nums參數: ", nums)
- my_tuple = (1, 2, 3)
- # 使用逆向收集,将my_tuple元組的元素傳給nums參數
- foo('fkit', *my_tuple)
上面程式中,調用将‘fkit’傳給 foo() 函數的 name 參數,然後使用逆向收集将 my_tuple 包含的多個元素傳給 nums 參數,nums 再将 my_tuple 的多個元素收內建元組。
運作上面代碼,将看到如下輸出結果:
name參數: fkit
nums參數: (1, 2, 3)
此外,也可使用如下方式調用 foo() 函數:
- # 使用逆向收集,将my_tuple元組的第一個元素傳給name參數,剩下參數傳給nums參數
- foo(*my_tuple)
此時程式會對 my_tuple 進行逆向收集,其中第一個元素傳給 name參數,後面剩下的元素傳給 nums 參數。運作上面代碼,将看到如下輸出結果:
name參數: 1
nums參數: (2, 3)
如果不使用逆向收集(不在元組參數之前添加星号),整個元組将會作為一個參數,而不是将元組的元素作為多個參數。例如按如下方式調用 foo() 函數:
- # 不使用逆向收集,my_tuple元組整體傳給name參數
- foo(my_tuple)
上面調用沒有使用逆向收集,是以 my_tuple 整體作為參數值傳給 name 參數。運作上面代碼,将看到如下輸出結果:
- def bar(book, price, desc):
- print(book, "VIP價格是:", price)
- print('描述資訊', desc)
- my_dict = {'price': 159, 'book': 'C語言中文網', 'desc': '這是一個精美而實用的網站'}
- # 按逆向收集的方式将my_dict的多個key-value傳給bar()函數
- bar(**my_dict)