2.15. 引數

函式可以用數種方式呼叫,其參數也可以用數種形態宣告。這些組合乍看之下令人卻步;但實務上三、四種模式幾乎涵蓋了一切。

2.15.1. 位置引數與關鍵字引數

最簡單的呼叫是按 位置 傳遞引數 -- 第一個值給第一個參數,第二個值給第二個參數,依此類推:

def rect(x, y, w, h):
    return (x, y, w, h)

rect(10, 20, 100, 50)

同樣的呼叫也可以按 關鍵字 傳遞引數,明確指名每個參數:

rect(x=10, y=20, w=100, h=50)

關鍵字引數與順序無關,並使呼叫具有自我說明性,代價是需要多打一些字。位置引數與關鍵字引數可以在單次呼叫中混用,但每個位置引數都必須出現在任何關鍵字引數之前:

rect(10, 20, w=100, h=50)         # OK
rect(x=10, 20, 100, 50)           # SyntaxError

2.15.2. 預設值

參數可以宣告一個預設值,以在呼叫者未提供時使用:

def greet(name, greeting="hello"):
    print(greeting, name)

greet("Alice")                    # hello Alice
greet("Alice", "hi")              # hi Alice
greet("Alice", greeting="hey")    # hey Alice

def 行中,具有預設值的參數必須位於沒有預設值的參數 之後

警告

預設值只會在 def 執行時評估一次 -- 而非每次呼叫時。使用可變的預設值([]{})會導致 同一個 物件在每次採用該預設值的呼叫之間共用。請改用 None 作為哨兵值:

def append_to(item, target=None):
    if target is None:
        target = []
    target.append(item)
    return target

2.15.3. 可變長度:*args**kwargs

* 為前綴的參數會將任何剩餘的位置引數收集進一個 tuple。以 ** 為前綴的參數會將任何剩餘的關鍵字引數收集進一個 dict。慣用的名稱是 argskwargs,但任何識別字都可以:

def report(label, *values, **options):
    print(label, values, options)

report("temps", 21, 22, 23, unit="C", precision=1)

輸出::

temps (21, 22, 23) {'unit': 'C', 'precision': 1}

函式很少需要兩者同時使用。最常見的用途是將引數從包裝函式轉發給內層呼叫:

def log_and_call(func, *args, **kwargs):
    print("calling", func.__name__)
    return func(*args, **kwargs)

呼叫 端的鏡像語法則會將一個可迭代物件解包成位置引數(*),或將一個 dict 解包成關鍵字引數(**):

point = (10, 20, 100, 50)
rect(*point)                      # same as rect(10, 20, 100, 50)

kwargs = {"x": 10, "y": 20, "w": 100, "h": 50}
rect(**kwargs)                    # same as rect(x=10, y=20, ...)

2.15.4. 僅限關鍵字的參數

在參數列表中單獨出現的 *(不附加在名稱上)會將其後的每個參數標記為 僅限關鍵字 -- 呼叫者必須使用名稱:

def crop(buffer, *, x, y, w, h):
    ...

crop(buffer, x=0, y=0, w=100, h=100)   # OK
crop(buffer, 0, 0, 100, 100)           # TypeError

對於布林旗標以及其他在呼叫端若僅有裸值便無法自我說明的引數,請使用這種方式。