Ta članek je bil objavljen kot del Blogathon o znanosti o podatkih
Predstavitev
Standardna knjižnica Python ima veliko odličnih modulov, ki pomagajo ohranjati vašo kodo čistejšo in enostavnejšo, funkcionalna orodja pa so zagotovo eden izmed
Predpomnjenje
Začnimo z nekaterimi najpreprostejšimi, a zmogljivimi funkcijami funkcijskih orodij modula. Začnimo s funkcijami predpomnjenja (pa tudi z dekoratorji) – lru_cache
,cache
in cached_property
. Prvi od njih – lru_cache
zagotavlja predpomnilnik zadnjih rezultatov izvajanja funkcij ali z drugimi besedami zapomni rezultat njihovega dela:
from functools import lru_cache
import requests @lru_cache(maxsize=32)
def get_with_cache(url): try: r = requests.get(url) return r.text except: return "Not Found" for url in ["https://google.com/", "https://reddit.com/", "https://google.com/", "https://google.com/"]: get_with_cache(url) print(get_with_cache.cache_info())
# CacheInfo(hits=2, misses=4, maxsize=32, currsize=4)
print(get_with_cache.cache_parameters())
# {'maxsize': 32, 'typed': False}
V tem primeru naredimo zahteve GET in predpomnimo njihove rezultate (do 32 rezultatov) z uporabo dekoratorja @lru_cache
. Če želite preveriti, ali predpomnjenje dejansko deluje, lahko preverite informacije o predpomnilniku funkcije z metodo cache_info
ki prikazuje število zadetkov in zadetkov predpomnilnika. Dekorater ponuja tudi metode clear_cache
in cache_parameters
za preklic predpomnjenih rezultatov oziroma testnih parametrov.
Če potrebujete bolj natančno predpomnjenje, lahko vključite izbirni argument typed=true, ki vam omogoča ločeno predpomnjenje različnih vrst argumentov.
Drug dekorater za predpomnjenje v funkcijskih orodjih je funkcija, imenovana preprosto cache
. To je preprost ovoj lru_cache
ki izpusti argument max_size, ga zmanjša in ne odstrani starih vrednosti.
Drug dekorater, ki ga lahko uporabite za predpomnjenje, je cached_property
. Kot pove že ime, se uporablja za predpomnilnik rezultatov atributov razreda. Ta mehanika je zelo uporabna, če imate lastnost, ki je draga za izračun, vendar ta ostaja enaka.
from functools import cached_property class Page: @cached_property def render(self, value): # Do something with supplied value... # Long computation that renders HTML page... return html
Ta preprost primer kaže. Kot je mogoče uporabiti lastnost cached, na primer za predpomnjenje upodobljene strani HTML, ki jo je treba uporabniku vedno znova prikazati. Enako je mogoče storiti za določene poizvedbe v bazi podatkov ali dolgotrajne matematične izračune.
Še ena lepotica cached_property
je, da se izvaja samo pri iskanju, zato nam omogoča spreminjanje vrednosti atributa. Po spremembi atributa se prej shranjena vrednost ne bo spremenila, namesto tega bo izračunana in predpomnjena nova vrednost. Prav tako lahko počistite predpomnilnik in vse, kar morate storiti, je odstraniti atribut.
Ta razdelek želim zaključiti s opozorilom o vseh zgornjih dekoratorjih – ne uporabljajte jih, če ima vaša funkcija nekaj stranskih učinkov ali če ob vsakem klicu ustvari spremenljive predmete, saj to očitno niso funkcije, ki jih želite predpomniti. .
Primerjava in naročanje
Verjetno že veste, da lahko v Pythonu implementirate primerjalne operatorje, kot je npr <
, >=
or ==
s lt
, gt
or eq
. Vendar pa je lahko zelo frustrirajoče spoznanje vsakega od njih eq
, lt
, le
, gt
or ge
. Na srečo, functools obstaja dekorater @total_ordering
ki nam lahko pri tem pomaga, kajti vse, kar moramo implementirati, je eq
ena od preostalih metod, preostali del dekoratorja pa bo ustvarjen samodejno.
from functools import total_ordering @total_ordering
class Number: def __init__(self, value): self.value = value def __lt__(self, other): return self.value Number(3))
# True
print(Number(1) = Number(15))
# True
print(Number(10) <= Number(2))
# False
Na ta način lahko izvajamo vse razširjene primerjalne operacije, čeprav imamo samo eq in ročno lt. Najbolj očitna prednost je priročnost, ki je, da vam ni treba pisati vseh teh dodatnih magičnih metod, verjetno pa je bolj pomembno zmanjšati količino kode in njeno boljšo berljivost.
preobremenitev
Verjetno so nas vsi naučili, da v Pythonu ni preobremenitve, vendar je pravzaprav preprost način, da ga implementirate z uporabo dveh funkcij iz funkcijskih orodij, in sicer z enojno odpremo in/ali enojno metodo pošiljanja. Te funkcije nam pomagajo pri implementaciji tega, kar bi imenovali algoritem za večkratno odpremo, ki omogoča dinamično tipkanim programskim jezikom, kot je Python, da razlikujejo med vrstami med izvajanjem.
Delno
Vsi delamo z različnimi zunanjimi knjižnicami ali ogrodji, od katerih mnoge zagotavljajo funkcije in vmesnike, ki od nas zahtevajo posredovanje povratnih klicev, na primer za asinhrone operacije ali poslušanje dogodkov. To ni nič novega, a kaj, če moramo poleg povratnega klica posredovati tudi nekaj argumentov. Tukaj pride v poštev funkcionalna orodja.partial
. Je lahko uporabljen partial
zamrzniti nekatere (ali vse) argumente funkcije z ustvarjanjem novega predmeta s poenostavljenim podpisom funkcije. Zmedeni? Oglejmo si nekaj praktičnih primerov:
def output_result(result, log=None): if log is not None: log.debug(f"Result is: {result}") def concat(a, b): return a + b import logging
from multiprocessing import Pool
from functools import partial logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("default") p = Pool()
p.apply_async(concat, ("Hello ", "World"), callback=partial(output_result, log=logger))
p.close()
p.join()
Zgornja koda prikazuje, kako jo lahko uporabite partial
prenesti funkcijo ( output_result
) skupaj z argumentom ( log=logger
) kot povratni klic. V tem primeru bomo uporabili multiprocessing.apply_async, ki asinhrono izračuna rezultat funkcije ( concat
) in vrne rezultat povratnega klica. Vendar pa apply_async
vedno bo posredoval rezultat kot prvi argument, in če želimo vključiti dodatne argumente, kot je v primeru log=logger, moramo uporabiti delni.
Upoštevali smo precej napreden primer uporabe, preprostejši primer pa bi bilo običajno ustvarjanje funkcije, ki piše v stderr namesto v stdout:
import sys
from functools import partial print_stderr = partial(print, file=sys.stderr)
print_stderr("This goes to standard error output")
S tem preprostim trikom smo ustvarili novo klicno funkcijo, ki bo vedno prestala file=sys.stderr
kot poimenovani argument za izhod, kar nam omogoča, da poenostavimo našo kodo in nam ni treba vsakič navesti vrednosti poimenovanega argumenta.
In še zadnji dober primer. Lahko uporabimo partial
v povezavi z malo znano funkcijo iter
ustvariti iterator s posredovanjem klicljivega predmeta in sentinel
in iter
, ki se lahko uporablja takole:
from functools import partial RECORD_SIZE = 64 # Read binary file...
with open("file.data", "rb") as file: records = iter(partial(file.read, RECORD_SIZE), b'') for r in records: # Do something with the record...
Običajno želimo pri branju datoteke ponoviti po vrsticah, v primeru binarnih podatkov pa bomo morda morali ponoviti zapise fiksne velikosti. To lahko storite tako, da ustvarite klicni objekt z uporabo partial
ki prebere določen kos podatkov in ga posreduje iter
da ustvarite iterator. Ta iterator nato pokliče funkcijo branja, dokler ne doseže konca datoteke, pri čemer vedno vzame samo določeno velikost kosa ( RECORD_SIZE
). Končno, ko je dosežen konec datoteke, vrednost sentinel
(b”) se vrne in ponovitev se ustavi.
Decorators
V prejšnjih razdelkih smo že govorili o nekaterih dekoraterjih, ne pa tudi o dekoratorjih, ki bi ustvarili več dekoraterjev. Eden takšnih okrasnikov so functools.wraps
. Če želite razumeti, zakaj ga potrebujete, poglejmo samo primer:
def decorator(func): def actual_func(*args, **kwargs): """Inner function within decorator, which does the actual work""" print(f"Before Calling {func.__name__}") func(*args, **kwargs) print(f"After Calling {func.__name__}") return actual_func @decorator
def greet(name): """Says hello to somebody""" print(f"Hello, {name}!") greet("Martin")
# Before Calling greet
# Hello, Martin!
# After Calling greet
Ta primer prikazuje, kako je mogoče izvesti preprost dekorater. Zavijemo funkcijo, ki izvaja določeno nalogo ( actual_func
) z zunanjim dekoratorjem in postane sam dekorater, ki ga lahko nato uporabimo za druge funkcije, na primer greet
. Ko pokličete funkcijo, greet
videli boste, da natisne sporočila iz obeh actual_func
in samostojno. Izgleda v redu, kajne? Toda kaj se zgodi, če naredimo to:
print(greet.__name__)
# actual_func
print(greet.__doc__)
# Inner function within decorator, which does the actual work
Ko pokličemo ime in dokumentacijo okrašene funkcije, ugotovimo, da so bili zamenjani z vrednostmi iz funkcije dekoraterja. To je slabo, saj ne moremo prepisati vseh imen naših funkcij in dokumentacije, ko uporabljamo kakšen dekorator. Kako je mogoče rešiti ta problem? Seveda s funkcijskimi orodji.wraps
:
from functools import wraps def decorator(func): @wraps(func) def actual_func(*args, **kwargs): """Inner function within decorator, which does the actual work""" print(f"Before Calling {func.__name__}") func(*args, **kwargs) print(f"After Calling {func.__name__}") return actual_func @decorator
def greet(name): """Says hello to somebody""" print(f"Hello, {name}!") print(greet.__name__)
# greet
print(greet.__doc__)
# Says hello to somebody
Edini namen funkcije wraps
je kopirati ime, dokumentacijo, seznam argumentov itd., da preprečite prepisovanje. Glede na to wraps
je tudi dekorater, lahko ga preprosto dodate v naš fact_func in problem je rešen!
Zmanjšaj
Nenazadnje v funkcijskih orodjih modula je to zmanjšanje. Morda iz drugih jezikov, morda ga poznate kot fold
(Haskell). Ta funkcija vzame iterable in zloži (doda) vse njegove vrednosti v eno. Za to obstaja veliko aplikacij, na primer:
from functools import reduce
import operator def product(iterable): return reduce(operator.mul, iterable, 1) def factorial(n): return reduce(operator.mul, range(1, n)) def sum(numbers): # Use `sum` function from standard library instead return reduce(operator.add, numbers, 1) def reverse(iterable): return reduce(lambda x, y: y+x, iterable) print(product([1, 2, 3]))
# 6
print(factorial(5))
# 24
print(sum([2, 6, 8, 3]))
# 20
print(reverse("hello"))
# olleh
Kot lahko vidite iz kode, reduce
lahko poenostavi ali zgosti kodo v eno vrstico, ki bi bila sicer veliko daljša. Glede na to je običajno slaba ideja zlorabljati to funkcijo samo zaradi krčenja kode in jo narediti "pametnejšo", saj hitro postane strašljiva in neberljiva. Zato ga je po mojem mnenju treba uporabljati zmerno.
In če se spomnite tega reduce
pogosto skrajša vse na eno vrstico, se lahko odlično kombinira z partial
:
product = partial(reduce, operator.mul) print(product([1, 2, 3]))
# 6
In končno, če potrebujete več kot le končni "strt" rezultat, potem lahko uporabite accumulate
– iz še enega odličnega modula itertools
. Za izračun največje vrednosti se lahko uporabi na naslednji način:
from itertools import accumulate data = [3, 4, 1, 3, 5, 6, 9, 0, 1] print(list(accumulate(data, max)))
# [3, 4, 4, 4, 5, 6, 9, 9, 9]
zaključek
Kot lahko vidite funkcijska orodja, obstaja veliko uporabnih funkcij in okrasnikov, ki vam lahko olajšajo življenje, vendar je to le vrh ledene gore. Kot sem rekel na začetku, je v standardni knjižnici Python veliko funkcij, ki vam pomagajo pisati boljšo kodo, zato lahko poleg funkcij, ki smo jih tukaj obravnavali, posvetite pozornost še drugim modulom, kot je npr. operator
or itertool.
Za kakršna koli vprašanja lahko pritisnete moje polje za komentar. Poskušal bom rešiti vaše vložke in upam, da vam bom dal želene rezultate. Lahko me kontaktirate tudi na LinkedInu:-
https://www.linkedin.com/in/shivani-sharma-aba6141b6/
Mediji, prikazani v tem članku, niso v lasti Analytics Vidhya in se uporabljajo po presoji avtorja.
Podobni
- '
- "
- 9
- Dodatne
- algoritem
- vsi
- analitika
- aplikacije
- Argumenti
- članek
- Beauty
- BEST
- Pasovi
- klic
- spremenite
- Koda
- Izračunajte
- Ustvarjanje
- datum
- Baze podatkov
- Dispatch
- itd
- dogodki
- izvedba
- končno
- prva
- Zamrzne
- funkcija
- dobro
- veliko
- priročen
- tukaj
- Kako
- HTTPS
- Ideja
- Podatki
- IT
- vzdrževanje
- jeziki
- Knjižnica
- vrstica
- Seznam
- Poslušanje
- Long
- iskanje
- Izdelava
- math
- mediji
- in sicer
- Imena
- številke
- Ok
- operacije
- Mnenje
- Ostalo
- Plačajte
- bazen
- moč
- Programiranje
- programskih jezikov
- nepremičnine
- Python
- reading
- evidence
- zmanjša
- REST
- Rezultati
- vrne
- Znanost
- Enostavno
- Velikosti
- So
- SOLVE
- Začetek
- Test
- čas
- us
- vrednost
- v
- besede
- delo
- deluje
- svet
- X