Funkcja partial pojawiła się w standardowej bibliotece Pythona (moduł functools) od Pythona 2.5, aby wdrożyć wzorzec karowania i częściowe zastosowanie argumentów do funkcji. partialmethod pojawił się z Pythonem 3.4 dla analogicznego zastosowania w metodach klas.
Często w rzeczywistych projektach pojawia się potrzeba zablokowania części argumentów funkcji, aby uzyskać nową funkcję z "zapamiętanymi" wartościami niektórych argumentów. Jest to wygodne dla callbacków, szablonów przekazywania argumentów lub dla zwiększenia czytelności kodu, zwłaszcza w programowaniu funkcyjnym i przy korzystaniu z API, oczekujących określonego stylu funkcji.
Funkcja partial zwraca nowy obiekt-funkcję, w którą "twardo" przefiltrowane (zablokowane) są niektóre z przekazanych argumentów lub argumentów kluczowych. partialmethod implementuje ten sam sposób dla metod klas, poprawnie wspierając mechanikę przekazywania self/cls.
Przykład kodu:
from functools import partial, partialmethod def power(base, exponent): return base ** exponent # Zablokowanie wykładnika = 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
Kluczowe cechy:
Czy można użyć partial dla metod klasy, aby uzyskać analogię do partialmethod?
Nie, partial nie obsługuje self/cls poprawnie, przy zastosowaniu do metody klasy nie działa w oczekiwany sposób: self nie zostanie automatycznie podstawione.
class C: def m(self, x, y): return x + y wrong = partial(m, y=2) # Niepoprawnie!
Przy wywołaniu c.wrong(5) wystąpi TypeError, ponieważ self nie zostanie automatycznie przekazane.
Czy obiekt utworzony przez partial to funkcja?
Tak, wynik działania partial to obiekt, który zachowuje się jak funkcja, wspiera wywołanie, nazwę, dokumentację itd., ale to nie jest zwykła funkcja, to obiekt klasy partial, implementujący protokół call.
from functools import partial f = partial(pow, 2) print(type(f)) # <class 'functools.partial'>
Czy partial działa z domyślnymi argumentami funkcji?
Tak, partial może "nadpisać" wartości domyślne w wewnętrznej funkcji; jeśli przekazane do partial argumenty, mają one pierwszeństwo przed wartościami domyślnymi w samej funkcji. Ważne jest jednak, aby nie duplikować wartości, w przeciwnym razie wystąpi błąd.
Programista stosuje partial dla metody klasy zamiast 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'
Zalety:
Wady:
Zamiast tego stosuje się 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
Zalety:
Wady: