functools
Narzędzia do pracy z funkcjami: zapamiętywanie wyników (lru_cache), częściowe wywołania (partial) i zwijanie kolekcji (reduce).
Przykład
#from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
print(fib(10))
print(fib(80))
print(fib.cache_info())Bez @lru_cache obliczenie fib(80) wymagałoby kilkudziesięciu biliardów wywołań funkcji, czyli dziesiątek lat pracy nawet szybkiego komputera. Z pamięcią podręczną każda wartość jest liczona tylko raz.
Definicja i zastosowanie
#Moduł functools zawiera narzędzia do pracy z funkcjami: takie, które przyjmują funkcje jako argumenty, opakowują je albo tworzą z nich nowe. Najczęściej używa się z niego dekoratora @lru_cache, funkcji partial() i reduce() oraz dekoratora @wraps, niezbędnego przy pisaniu własnych dekoratorów.
@lru_cache zapamiętuje wyniki funkcji dla użytych już argumentów. Przy kolejnym wywołaniu z tymi samymi argumentami wynik jest zwracany od razu, bez ponownego liczenia, co daje ogromne przyspieszenie przy kosztownych obliczeniach i rekurencji. Argumenty muszą być hashowalne (liczby, napisy, krotki), a wynik powinien zależeć tylko od nich. Statystyki trafień pokazuje metoda cache_info().
partial() tworzy nową funkcję z częścią argumentów ustawionych na stałe, np. partial(int, base=2) tworzy funkcję, która zamienia na liczby napisy zapisane w systemie dwójkowym. reduce() zwija kolekcję do jednej wartości: wywołuje funkcję dwuargumentową najpierw dla dwóch pierwszych elementów, potem dla wyniku i trzeciego elementu, i tak dalej. Do sum i maksimów prostsze są jednak sum() i max().
Składnia
#from functools import cache, lru_cache, partial, reduce, wraps
@lru_cache(maxsize=128)
def funkcja(argumenty):
...
nowa = partial(funkcja, *args, **kwargs)
wynik = reduce(funkcja, iterable, initial)Najważniejsze funkcje
#@lru_cache
dekorator
Zapamiętuje wyniki dla ostatnio użytych argumentów. Parametrmaxsize(domyślnie 128) określa, ile wyników pamiętać, aNoneusuwa limit.@cache
dekorator
Prostszy odpowiedniklru_cache(maxsize=None): pamięta wszystkie wyniki.partial()
funkcja
Zwraca nową funkcję z częścią argumentów ustawionych na stałe:partial(func, *args, **kwargs).reduce()
funkcja
Zwija kolekcję do jednej wartości:reduce(func, iterable, initial). Bezinitialpusta kolekcja zgłaszaTypeError.@wraps
dekorator
Używany we własnych dekoratorach: kopiuje nazwę i docstring opakowanej funkcji do wrappera.@total_ordering
dekorator klasy
Uzupełnia brakujące porównania na podstawie__eq__i jednej z metod__lt__,__le__,__gt__albo__ge__.@cached_property
dekorator metody
Zamienia metodę w atrybut liczony raz, przy pierwszym odczycie.
Więcej przykładów
#from functools import partial
def award(exp, name, reason="zadanie"):
return f"{name}: +{exp} EXP ({reason})"
small = partial(award, 5)
streak = partial(award, 20, reason="seria 7 dni")
print(small("Ania"))
print(streak("Kuba"))
from_binary = partial(int, base=2)
print(from_binary("1010"))from functools import reduce
scores = [72, 95, 64, 88]
print(reduce(lambda total, s: total + s, scores))
print(reduce(lambda best, s: s if s > best else best, scores))
updates = [{"level": 2}, {"points": 250}, {"level": 3}]
profile = reduce(lambda acc, change: {**acc, **change}, updates, {"name": "Ania"})
print(profile)
print(reduce(lambda a, b: a * b, [], 1))from functools import total_ordering
@total_ordering
class Level:
def __init__(self, number):
self.number = number
def __eq__(self, other):
return self.number == other.number
def __lt__(self, other):
return self.number < other.number
print(Level(3) >= Level(2), Level(1) <= Level(1), Level(5) > Level(7))Dobre praktyki
#- Nie używaj
@lru_cachedla funkcji z efektami ubocznymi, np. zapisem do pliku, losowaniem albo odczytem czasu. Dla zapamiętanych argumentów funkcja w ogóle się nie wykona. - Argumenty funkcji z pamięcią podręczną muszą być hashowalne. Listy zamień przed wywołaniem na krotki.
- Zamiast
reduce()do sumy, iloczynu czy maksimum użyjsum(),math.prod()imax(). Są czytelniejsze i szybsze.
Powiązane hasła
#- DekoratoryFunkcje, które opakowują inne funkcje i dodają im zachowanie, np. logowanie lub sprawdzanie uprawnień. Zapis @nazwa.
- lambdaKrótka funkcja anonimowa zapisana w jednym wyrażeniu.
- map()Wywołuje funkcję dla każdego elementu i zwraca iterator wyników.
- sum()Dodaje do siebie wszystkie liczby z kolekcji.
- @propertyZamienia metodę w atrybut: wartość jest wyliczana przy odczycie, a opcjonalny setter kontroluje zapis.
- itertoolsNarzędzia do pracy z iteratorami: łączenie, grupowanie, kombinacje i nieskończone ciągi.
Widzisz błąd albo brakuje przykładu? Napisz do nas.