Zapore Pythona: Kako ga uporabljati in zakaj?

V tej vadnici boste izvedeli o zaprtju Pythona, kako definirati zaprtje in razloge, zaradi katerih bi ga morali uporabiti.

Nelokalna spremenljivka v ugnezdeni funkciji

Preden se lotimo, kaj je zaprtje, moramo najprej razumeti, kaj je ugnezdena funkcija in nelokalna spremenljivka.

Funkcija, definirana znotraj druge funkcije, se imenuje ugnezdena funkcija. Vgnezdene funkcije lahko dostopajo do spremenljivk obsega, ki ga zajema.

V Pythonu so te ne-lokalne spremenljivke privzeto samo za branje in jih moramo izrecno razglasiti kot ne-lokalne (z uporabo nelokalne ključne besede), da jih lahko spremenimo.

Sledi primer ugnezdene funkcije, ki dostopa do ne-lokalne spremenljivke.

 def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) printer() # We execute the function # Output: Hello print_msg("Hello")

Izhod

 zdravo

Vidimo lahko, da je ugnezdena printer()funkcija lahko dostopala do nelokalne spremenljivke msg ograjevalne funkcije.

Določitev funkcije zapiranja

Kaj bi se zgodilo v zgornjem primeru, če zadnja vrstica funkcije print_msg()vrne printer()funkcijo, namesto da bi jo poklicala? To pomeni, da je bila funkcija definirana na naslednji način:

 def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) return printer # returns the nested function # Now let's try calling this function. # Output: Hello another = print_msg("Hello") another()

Izhod

 zdravo

To je nenavadno.

print_msg()Funkcijo je bil imenovan z vrvico "Hello"in se vrne funkcija je vezana na ime drugega. Ob klicu another()se je sporočilo še vedno zapomnilo, čeprav smo že zaključili z izvajanjem print_msg()funkcije.

Ta tehnika, s katero se nekateri podatki ( "Hellov tem primeru) pritrdijo na kodo, se v Pythonu imenuje zaprtje .

Ta vrednost v obsegu, ki ga zajema, se zapomni, tudi če spremenljivka izstopi iz obsega ali pa je funkcija sama odstranjena iz trenutnega imenskega prostora.

Poskusite zagnati naslednje v lupini Python, da si ogledate izhodne podatke.

 >>> del print_msg >>> another() Hello >>> print_msg("Hello") Traceback (most recent call last):… NameError: name 'print_msg' is not defined

Tu vrnjena funkcija še vedno deluje, tudi če je bila izvirna funkcija izbrisana.

Kdaj imamo zapore?

Kot je razvidno iz zgornjega primera, imamo zaprtje v Pythonu, ko se ugnezdena funkcija sklicuje na vrednost v obsegu, ki ga zapira.

Merila, ki jih je treba izpolniti za zapiranje v Pythonu, so povzeta v naslednjih točkah.

  • Imeti moramo ugnezdeno funkcijo (funkcija znotraj funkcije).
  • Vgnezdena funkcija se mora sklicevati na vrednost, določeno v zapiralni funkciji.
  • Omejevalna funkcija mora vrniti ugnezdeno funkcijo.

Kdaj uporabiti zapore?

Za kaj so torej zapiranja dobra?

Zapiranja se lahko izognejo uporabi globalnih vrednosti in zagotavljajo neko obliko skrivanja podatkov. Lahko tudi objektno usmerjeno rešitev problema.

Kadar je v razredu le malo metod (v večini primerov ena metoda), lahko zaprtja zagotovijo nadomestno in elegantnejšo rešitev. Ko pa se število atributov in metod poveča, je bolje uporabiti razred.

Tu je preprost primer, ko je zaprtje morda bolj zaželeno kot definiranje razreda in izdelava predmetov. Toda preferenca je vaša.

 def make_multiplier_of(n): def multiplier(x): return x * n return multiplier # Multiplier of 3 times3 = make_multiplier_of(3) # Multiplier of 5 times5 = make_multiplier_of(5) # Output: 27 print(times3(9)) # Output: 15 print(times5(3)) # Output: 30 print(times5(times3(2)))

Izhod

 27 15 30

Python Decorators pogosto uporabljajo tudi zapore.

Na koncu je dobro poudariti, da je mogoče ugotoviti vrednosti, ki so priložene v funkciji zapiranja.

Vsi funkcijski predmeti imajo __closure__atribut, ki vrne nabor celičnih predmetov, če gre za funkcijo zapiranja. Glede na zgornji primer vemo times3in times5so funkcije zapiranja.

 >>> make_multiplier_of.__closure__ >>> times3.__closure__ (,)

Objekt celice ima atribut cell_contents, ki hrani zaprto vrednost.

 >>> times3.__closure__(0).cell_contents 3 >>> times5.__closure__(0).cell_contents 5

Zanimive Članki...