La funzione partial è apparsa nella libreria standard di Python (modulo functools) a partire da Python 2.5, per implementare il pattern del currying e l'applicazione parziale degli argomenti a una funzione. partialmethod è apparso con Python 3.4 per un'applicazione analoga nei metodi delle classi.
Spesso nei progetti reali sorge la necessità di fissare parte degli argomenti di una funzione, per ottenere una nuova funzione con "valori memorizzati" di alcuni argomenti. Questo è utile per i callback, i modelli di passaggio degli argomenti, o per aumentare la leggibilità del codice, specialmente nella programmazione funzionale e quando si utilizza un'API che si aspetta un certo stile di funzioni.
La funzione partial restituisce un nuovo oggetto-funzione, in cui alcuni degli argomenti o argomenti chiave passati sono "fissati" (hard-coded). partialmethod implementa lo stesso approccio per i metodi delle classi, supportando correttamente la meccanica del passaggio di self/cls.
Esempio di codice:
from functools import partial, partialmethod def power(base, exponent): return base ** exponent # Fissiamo l'esponente = 2 square = partial(power, exponent=2) print(square(5)) # 25 class Math: def power(self, base, exponent): return base ** exponent square = partialmethod(power, exponent=2) m = Math() print(m.square(5)) # 25
Caratteristiche chiave:
Si può usare partial per i metodi di classe, per ottenere un analogo di partialmethod?
No, partial non gestisce correttamente self/cls, quando applicato a un metodo di classe non funziona come previsto: self non verrà sostituito automaticamente.
class C: def m(self, x, y): return x + y wrong = partial(m, y=2) # Sbagliato!
Chiamando c.wrong(5) si otterrà un TypeError, perché self non verrà passato automaticamente.
L'oggetto creato tramite partial è una funzione?
Sì, il risultato dell'applicazione di partial è un oggetto che si comporta come una funzione, supporta la chiamata, il nome, la docstring, ecc., ma non è una funzione normale, è un oggetto della classe partial, che implementa il protocollo call.
from functools import partial f = partial(pow, 2) print(type(f)) # <class 'functools.partial'>
Funziona partial con gli argomenti predefiniti della funzione?
Sì, partial può "sovrascrivere" i valori predefiniti nella funzione interna; se vengono passati argomenti a partial, hanno la priorità sui valori predefiniti nella funzione stessa. Tuttavia, è importante non duplicare valori, altrimenti si otterrà un errore.
Sviluppatore applica partial per un metodo di classe invece di partialmethod:
class MyClass: def f(self, x, y): ... squared = partial(f, y=2) ... obj = MyClass() obj.squared(5) # TypeError: missing 1 required positional argument: 'self'
Vantaggi:
Svantaggi:
Invece, si applica partialmethod:
from functools import partialmethod class MyClass: def f(self, x, y): return x + y squared = partialmethod(f, y=2) obj = MyClass() print(obj.squared(5)) # 7
Vantaggi:
Svantaggi: