1. 程式人生 > >【python筆記】函式_03_函式的引數

【python筆記】函式_03_函式的引數

實參:鑑於函式定義中可能包含多個實參,因此函式呼叫可能包含多個實參。

  1. 向函式傳遞實參函式的方式很多,可使用位置實參,這就要求實參的順序與形參的順序相同
  2. 也可使用關鍵字實參,其中每個實參都有變數名和值組成;
  3. 還可使用列表和字典

1.位置實參

  1. 定義:你呼叫函式時,python必須將函式呼叫中的每個實參都關聯到函式定義的一個形參。為此,最簡單的關聯方式是基於實參的順序。這種關聯方式被稱為位置實參
  2. 可以呼叫函式多次
  3. 位置引數的順序很重要

2.關鍵字實參

  1. 定義:關鍵字實參是傳遞給函式的名稱-值對。你直接在實參中將名稱和值關聯起來了,因此向引數傳遞實參時不會混淆。關鍵字實參讓你無需考慮函式呼叫中的實參順序,還清楚地指出了函式呼叫中各個值的用途。
def describe_pet(animal_type, pet_name):
 """顯示寵物的資訊"""
 print("\nI have a " + animal_type + ".")
 print("My " + animal_type + "'s name is " + pet_name.title() + ".")

describe_pet(animal_type='hamster', pet_name='harry') 
  1. 注意:使用關鍵字實參時,務必準確地指出函式定義中的形參名。

3.預設引數

  1. 定義:編寫函式時,可給每個形參指定預設值。在呼叫函式中給形參提供了實參時,python將使用指定的實參值;否則,將使用形參的預設值。因此,給形參指定預設值後,可在函式呼叫中省略相應的實參。使用預設值可簡化函式呼叫,還可以清楚地指出函式的典型用法。
def describe_pet(pet_name, animal_type='dog'):
 """顯示寵物的資訊"""
 print("\nI have a " + animal_type + ".")
 print("My " + animal_type + "'s name is " + pet_name.title() + ".") 
 
describe_pet(pet_name='willie') 
  1. 注意:使用預設值時,在形參列表中必須先列出沒有預設值的形參,再列出有預設值的實參。這讓Python依然能夠正確地解讀位置實參
def add_end(L=[]):
    L.
append('END') return L
>>> add_end()
['END']
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']
  1. 定義預設引數要牢記一點:預設引數必須指向不變物件!
def add_end(L=None):
    if L is None:
        L = []
    L.append('END')
    return L
>>> add_end()
['END']
>>> add_end()
['END']
  1. 為什麼要設定str 、None這樣的不變物件呢? 因為不變物件一旦建立,物件內部的資料就不能被修改,這樣就減少了由於修改資料導致的錯誤。此外,由於物件不變,多工環境下同時讀取物件不需要加鎖,同時讀一點問題都沒有。我們在編寫程式時,如果可以設計一個不變物件,那就儘量設計成不變物件。

4.可變引數

  1. 定義:可變引數就是傳入的引數個數時可變的,可以是1個、2個、到任意個,還可以是0個。
  2. 我們把函式的引數改為可變引數:
def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum
  1. 定義可變引數和定義一個listtuple引數相比,僅僅在引數前面加了一個*號。在函式內部,引數numbers接收到的是一個tuple,因此,函式程式碼完全不變。但是,呼叫該函式時,可以傳入任意個引數,包括0個引數:
>>> calc(1, 2)
5
>>> calc()
0
  1. Python允許你在listtuple前面加一個*號,把listtuple的元素變成可變引數傳進去:
>>> nums = [1, 2, 3]
>>> calc(*nums)
14

5.關鍵字引數

  1. 關鍵字引數允許你傳入0個或任意個含引數名的引數,這些關鍵字引數在函式內部自動組裝為一個dict
  2. **關鍵字引數有什麼用?**它可以擴充套件函式的功能。比如,在person函式裡,我們保證能接收到name和age這兩個引數,但是,如果呼叫者願意提供更多的引數,我們也能收到。試想你正在做一個使用者註冊的功能,除了使用者名稱和年齡是必填項外,其他都是可選項,利用關鍵字引數來定義這個函式就能滿足註冊的需求。
  3. 和可變引數類似,也可以先組裝出一個dict,然後,把該dict轉換為關鍵字引數傳進去:
def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
  1. **extra表示把extra這個dict的所有key-value用關鍵字引數傳入到函式的**kw引數,kw將獲得一個dict,注意kw獲得的dictextra的一份拷貝,對kw的改動不會影響到函式外的extra。

6.命名關鍵字引數

  1. 如果要限制關鍵字引數的名字,就可以用命名關鍵字引數,例如,只接收cityjob作為關鍵字引數。這種方式定義的函式如下:
def person(name, age, *, city, job):
    print(name, age, city, job)
  1. 和關鍵字引數**kw不同,命名關鍵字引數需要一個特殊分隔符*,*後面的引數被視為命名關鍵字引數。
  2. 呼叫方式如下:
>>> person('Jack', 24, city='Beijing', job='Engineer')
Jack 24 Beijing Engineer
  1. 如果函式定義中已經有了一個可變引數,後面跟著的命名關鍵字引數就不再需要一個特殊分隔符*了:
def person(name, age, *args, city, job):
    print(name, age, args, city, job)
  1. 命名關鍵字引數必須傳入引數名,這和位置引數不同。如果沒有傳入引數名,呼叫將報錯:
>>> person('Jack', 24, 'Beijing', 'Engineer')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: person() takes 2 positional arguments but 4 were given
  1. 由於呼叫時缺少引數名cityjob,Python直譯器把這4個引數均視為位置引數,但person()函式僅接受2個位置引數。

  2. 命名關鍵字引數可以有預設值,從而簡化呼叫:

def person(name, age, *, city='Beijing', job):
    print(name, age, city, job)
  1. 由於命名關鍵字引數city具有預設值,呼叫時,可不傳入city引數:
>>> person('Jack', 24, job='Engineer')
Jack 24 Beijing Engineer
  1. 使用命名關鍵字引數時,要特別注意,如果沒有可變引數,就必須加一個*作為特殊分隔符。如果缺少*Python直譯器將無法識別位置引數和命名關鍵字引數:
def person(name, age, city, job):
    # 缺少 *,city和job被視為位置引數
    pass

7.引數組合

  1. 在Python中定義函式,可以用必選引數、預設引數、可變引數、關鍵字引數和命名關鍵字引數,這5種引數都可以組合使用。但是請注意,引數定義的順序必須是:必選引數、預設引數、可變引數、命名關鍵字引數和關鍵字引數。
def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
>>> f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
  1. 最神奇的是通過一個tuple和dict,你也可以呼叫上述函式:
>>> args = (1, 2, 3, 4)
>>> kw = {'d': 99, 'x': '#'}
>>> f1(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
>>> args = (1, 2, 3)
>>> kw = {'d': 88, 'x': '#'}
>>> f2(*args, **kw)
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}

小結

  1. Python的函式具有非常靈活的引數形態,既可以實現簡單的呼叫,又可以傳入非常複雜的引數。
  2. 預設引數一定要用不可變物件,如果是可變物件,程式執行時會有邏輯錯誤!
  3. 要注意定義可變引數和關鍵字引數的語法:
  4. *args是可變引數,args接收的是一個tuple
  5. **kw是關鍵字引數,kw接收的是一個dict
  6. 以及呼叫函式時如何傳入可變引數和關鍵字引數的語法:
  7. 可變引數既可以直接傳入:func(1, 2, 3),又可以先組裝listtuple,再通過*args傳入:func(*(1, 2, 3));
  8. 關鍵字引數既可以直接傳入:func(a=1, b=2),又可以先組裝dict,再通過**kw傳入:func(**{'a': 1, 'b': 2})
  9. 使用*args**kw是Python的習慣寫法,當然也可以用其他引數名,但最好使用習慣用法。
  10. 命名的關鍵字引數是為了限制呼叫者可以傳入的引數名,同時可以提供預設值。
  11. 定義命名的關鍵字引數在沒有可變引數的情況下不要忘了寫分隔符*,否則定義的將是位置引數。