天天看點

Python可變參數函數用法詳解

Python可變參數函數用法詳解

來自:http://c.biancheng.net/view/2257.html

很多程式設計語言都允許定義個數可變的參數,這樣可以在調用函數時傳入任意多個參數。Python 當然也不例外,Python 允許在形參前面添加一個星号(*),這樣就意味着該參數可接收多個參數值,多個參數值被當成元組傳入。

下面程式定義了一個形參個數可變的函數:

  1. # 定義了支援參數收集的函數
  2. def test(a, *books) :
  3. print(books)
  4. # books被當成元組處理
  5. for b in books :
  6. print(b)
  7. # 輸出整數變量a的值
  8. print(a)
  9. # 調用test()函數
  10. test(5 , "C語言中文網" , "Python教程")

運作上面程式,将看到如下運作結果:

('C語言中文網', 'Python教程')

C語言中文網

Python教程

5

從上面的運作結果可以看出,當調用 test() 函數時,books 參數可以傳入多個字元串作為參數值。從 test() 的函數體代碼來看,參數收集的本質就是一個元組: Python 會将傳給 books 參數的多個值收內建一個元組。

Python 允許個數可變的形參可以處于形參清單的任意位置(不要求是形參清單的最後一個參數),但 Python 要求一個函數最多隻能帶一個支援“普通”參數收集的形參。例如如下程式:

  1. def test(*books ,num) :
  2. print(num)
  3. test("C語言中文網", "Python教程", num = 20)

正如從上面程式中所看到的,test() 函數的第一個參數就是個數可變的形參,由于該參數可接收個數不等的參數值,是以如果需要給後面的參數傳入參數值,則必須使用關鍵字參數,否則程式會把所傳入的多個值都當成是傳給 books 參數的。

Python 還可以收集關鍵字參數,此時 Python 會将這種關鍵字參數收內建字典。為了讓 Python 能收集關鍵字參數,需要在參數前面添加兩個星号。在這種情況下,一個函數可同時包含一個支援“普通”參數收集的參數和一個支援關鍵字參數收集的參數。例如如下代碼:

  1. def test(x, y, z=3, *books, **scores) :
  2. print(x, y, z)
  3. print(scores)
  4. 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 參數将是一個空元組;接下來的兩個關鍵字參數将會被收內建字典。運作上面代碼,會看到如下輸出結果:

()

逆向參數收集

所謂逆向參數收集,指的是在程式己有清單、元組、字典等對象的前提下,把它們的元素“拆開”後傳給函數的參數。

逆向參數收集需要在傳入的清單、元組參數之前添加一個星号,在字典參數之前添加兩個星号。例如如下代碼:

  1. def test(name, message):
  2. print("使用者是: ", name)
  3. print("歡迎消息: ", message)
  4. my_list = ['孫悟空', '歡迎來C語言中文網']
  5. test(*my_list)

程式中定義了一個需要兩個參數的函數,而 my_list 清單包含兩個元素,為了讓程式将 my_list 清單的兩個元素傳給 test() 函數,程式在傳入的 my_list 參數之前添加了一個星号。

實際上,即使是支援收集的參數,如果程式需要将一個元組傳給該參數,那麼同樣需要使用逆向收集。例如如下代碼:

  1. def foo(name, *nums):
  2. print("name參數: ", name)
  3. print("nums參數: ", nums)
  4. my_tuple = (1, 2, 3)
  5. # 使用逆向收集,将my_tuple元組的元素傳給nums參數
  6. foo('fkit', *my_tuple)

上面程式中,調用将‘fkit’傳給 foo() 函數的 name 參數,然後使用逆向收集将 my_tuple 包含的多個元素傳給 nums 參數,nums 再将 my_tuple 的多個元素收內建元組。

運作上面代碼,将看到如下輸出結果:

name參數:  fkit

nums參數:  (1, 2, 3)

此外,也可使用如下方式調用 foo() 函數:

  1. # 使用逆向收集,将my_tuple元組的第一個元素傳給name參數,剩下參數傳給nums參數
  2. foo(*my_tuple)

此時程式會對 my_tuple 進行逆向收集,其中第一個元素傳給 name參數,後面剩下的元素傳給 nums 參數。運作上面代碼,将看到如下輸出結果:

name參數:  1

nums參數:  (2, 3)

如果不使用逆向收集(不在元組參數之前添加星号),整個元組将會作為一個參數,而不是将元組的元素作為多個參數。例如按如下方式調用 foo() 函數:

  1. # 不使用逆向收集,my_tuple元組整體傳給name參數
  2. foo(my_tuple)

上面調用沒有使用逆向收集,是以 my_tuple 整體作為參數值傳給 name 參數。運作上面代碼,将看到如下輸出結果:

  1. def bar(book, price, desc):
  2. print(book, "VIP價格是:", price)
  3. print('描述資訊', desc)
  4. my_dict = {'price': 159, 'book': 'C語言中文網', 'desc': '這是一個精美而實用的網站'}
  5. # 按逆向收集的方式将my_dict的多個key-value傳給bar()函數
  6. bar(**my_dict)