2.15. Argomenti

Una funzione può essere chiamata in diversi modi e i suoi parametri possono essere dichiarati in diverse forme. All’inizio le combinazioni sembrano intimidatorie; in pratica tre o quattro schemi coprono quasi tutto.

2.15.1. Argomenti posizionali e per parola chiave

La chiamata più semplice passa gli argomenti per posizione: il primo valore va al primo parametro, il secondo al secondo, e così via:

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

rect(10, 20, 100, 50)

La stessa chiamata può passare gli argomenti per parola chiave, nominando esplicitamente ciascun parametro:

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

Gli argomenti per parola chiave sono indipendenti dall’ordine e rendono le chiamate auto-documentate, al costo di scrivere di più. Argomenti posizionali e per parola chiave possono coesistere in un’unica chiamata, ma ogni argomento posizionale deve precedere qualsiasi argomento per parola chiave:

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

2.15.2. Valori predefiniti

Un parametro può dichiarare un valore predefinito da usare quando il chiamante non ne fornisce uno:

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

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

Nella riga def, i parametri con valori predefiniti devono venire dopo quelli senza valori predefiniti.

Avvertimento

I valori predefiniti vengono valutati una sola volta, quando viene eseguito il def, non a ogni chiamata. Usare un valore predefinito mutabile ([], {}) fa sì che lo stesso oggetto venga condiviso tra tutte le chiamate che usano il valore predefinito. Usa invece None come sentinella:

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

2.15.3. Lunghezza variabile: *args e **kwargs

Un parametro preceduto da * raccoglie tutti gli argomenti posizionali rimanenti in una tuple. Un parametro preceduto da ** raccoglie tutti gli argomenti per parola chiave rimanenti in un dict. I nomi convenzionali sono args e kwargs, ma funziona qualsiasi identificatore:

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

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

Output:

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

Raramente una funzione ha bisogno di entrambi. L’uso più comune è inoltrare gli argomenti da un wrapper a una chiamata interna:

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

La sintassi speculare nel sito di chiamata spacchetta un iterabile in argomenti posizionali (*) oppure un dict in argomenti per parola chiave (**):

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. Parametri solo per parola chiave

Un * da solo nell’elenco dei parametri (non collegato a un nome) contrassegna ogni parametro successivo come solo per parola chiave: il chiamante deve usare il nome:

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

Usalo per i flag booleani e per altri argomenti in cui un valore nudo nel sito di chiamata non sarebbe auto-esplicativo.