Python-sluitingen: hoe te gebruiken en waarom?

In deze tutorial leer je over Python-sluiting, hoe je een sluiting definieert en de redenen waarom je deze zou moeten gebruiken.

Niet-lokale variabele in een geneste functie

Voordat we ingaan op wat een sluiting is, moeten we eerst begrijpen wat een geneste functie en niet-lokale variabele is.

Een functie die binnen een andere functie is gedefinieerd, wordt een geneste functie genoemd. Geneste functies hebben toegang tot variabelen van het omsluitende bereik.

In Python zijn deze niet-lokale variabelen standaard alleen-lezen en we moeten ze expliciet als niet-lokaal declareren (met een niet-lokaal sleutelwoord) om ze te kunnen wijzigen.

Hieronder volgt een voorbeeld van een geneste functie die toegang heeft tot een niet-lokale variabele.

 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")

Uitvoer

 Hallo

We kunnen zien dat de geneste printer()functie toegang had tot de niet-lokale msg-variabele van de omsluitende functie.

Een sluitfunctie definiëren

Wat zou er in het bovenstaande voorbeeld gebeuren als de laatste regel van de functie de functie print_msg()retourneert in printer()plaats van deze aan te roepen? Dit betekent dat de functie als volgt is gedefinieerd:

 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()

Uitvoer

 Hallo

Dat is ongebruikelijk.

De print_msg()functie werd aangeroepen met de string "Hello"en de geretourneerde functie was gebonden aan de naam een ​​andere. Bij het bellen another()werd het bericht nog steeds onthouden, hoewel we al klaar waren met het uitvoeren van de print_msg()functie.

Deze techniek waarmee sommige gegevens ( "Helloin dit geval) aan de code worden gekoppeld, wordt in Python sluiting genoemd .

Deze waarde in het omsluitende bereik wordt onthouden, zelfs als de variabele buiten het bereik valt of als de functie zelf uit de huidige naamruimte wordt verwijderd.

Probeer het volgende uit te voeren in de Python-shell om de uitvoer te zien.

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

Hier werkt de geretourneerde functie nog steeds, zelfs als de oorspronkelijke functie is verwijderd.

Wanneer zijn er sluitingen?

Zoals blijkt uit het bovenstaande voorbeeld, hebben we een sluiting in Python wanneer een geneste functie verwijst naar een waarde in het omsluitende bereik.

De criteria waaraan moet worden voldaan om sluiting in Python te maken, worden samengevat in de volgende punten.

  • We moeten een geneste functie hebben (functie binnen een functie).
  • De geneste functie moet verwijzen naar een waarde die is gedefinieerd in de omsluitende functie.
  • De omsluitende functie moet de geneste functie teruggeven.

Wanneer sluitingen gebruiken?

Dus waar zijn sluitingen goed voor?

Sluitingen kunnen het gebruik van globale waarden vermijden en bieden een vorm van gegevens verbergen. Het kan ook een objectgeoriënteerde oplossing voor het probleem bieden.

Als er weinig methoden zijn (in de meeste gevallen één methode) die in een klasse kunnen worden geïmplementeerd, kunnen sluitingen een alternatieve en elegantere oplossing bieden. Maar als het aantal attributen en methoden groter wordt, is het beter om een ​​klasse te implementeren.

Hier is een eenvoudig voorbeeld waarbij een sluiting misschien meer de voorkeur heeft dan het definiëren van een klasse en het maken van objecten. Maar de voorkeur is helemaal aan jou.

 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)))

Uitvoer

 27 15 30

Python Decorators maken ook veel gebruik van sluitingen.

Ter afsluiting is het goed om erop te wijzen dat de waarden die worden ingesloten in de sluitfunctie achterhaald kunnen worden.

Alle functieobjecten hebben een __closure__attribuut dat een tupel celobjecten retourneert als het een sluitfunctie is. Verwijzend naar het bovenstaande voorbeeld, we kennen times3en times5zijn sluitfuncties.

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

Het celobject heeft het attribuut cell_contents waarin de gesloten waarde wordt opgeslagen.

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

Interessante artikelen...