Python-stängningar: Hur man använder det och varför?

I den här handledningen lär du dig om Python-stängning, hur du definierar en stängning och anledningarna till att du ska använda den.

Icke-lokal variabel i en kapslad funktion

Innan vi går in i vad en förslutning är måste vi först förstå vad en kapslad funktion och icke-lokal variabel är.

En funktion definierad i en annan funktion kallas en kapslad funktion. Kapslade funktioner har åtkomst till variabler i det bifogade omfånget.

I Python är dessa icke-lokala variabler skrivskyddade som standard och vi måste deklarera dem uttryckligen som icke-lokala (med icke-lokalt nyckelord) för att kunna ändra dem.

Följande är ett exempel på en kapslad funktion som får åtkomst till en icke-lokal variabel.

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

Produktion

 Hej

Vi kan se att den kapslade printer()funktionen kunde komma åt den icke-lokala msg-variabeln för den omslutande funktionen.

Definiera en stängningsfunktion

I exemplet ovan, vad skulle hända om den sista raden i funktionen print_msg()returnerade printer()funktionen istället för att ringa den? Detta betyder att funktionen definierades enligt följande:

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

Produktion

 Hej

Det är ovanligt.

Den print_msg()funktionen kallades med strängen "Hello"och åter funktion var bunden till namnet annan. Vid samtal another()kom meddelandet fortfarande ihåg även om vi redan hade slutfört print_msg()funktionen.

Denna teknik genom vilken vissa data ( "Helloi det här fallet) kopplas till koden kallas stängning i Python .

Det här värdet i det bifogade omfånget kommer ihåg även när variabeln går utanför omfånget eller själva funktionen tas bort från det aktuella namnområdet.

Försök att köra följande i Python-skalet för att se utdata.

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

Här fungerar den returnerade funktionen fortfarande även när den ursprungliga funktionen togs bort.

När har vi stängningar?

Som framgår av exemplet ovan har vi en stängning i Python när en kapslad funktion refererar till ett värde i dess omslutande omfång.

Kriterierna som måste uppfyllas för att skapa stängning i Python sammanfattas i följande punkter.

  • Vi måste ha en kapslad funktion (funktion inuti en funktion).
  • Den kapslade funktionen måste referera till ett värde som definierats i den bifogade funktionen.
  • Den bifogade funktionen måste returnera den kapslade funktionen.

När ska man använda stängningar?

Så vad är stängningar bra för?

Stängningar kan undvika användning av globala värden och tillhandahåller någon form av datadömning. Det kan också ge en objektorienterad lösning på problemet.

När det finns få metoder (en metod i de flesta fall) som ska implementeras i en klass kan stängningar ge en alternativ och mer elegant lösning. Men när antalet attribut och metoder blir större är det bättre att genomföra en klass.

Här är ett enkelt exempel där en förslutning kan vara bättre än att definiera en klass och göra objekt. Men preferensen är helt din.

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

Produktion

 27 15 30

Python Decorators använder också omfattande förslutningar.

På en avslutande anteckning är det bra att påpeka att värdena som stängs in i stängningsfunktionen kan hittas.

Alla funktionsobjekt har ett __closure__attribut som returnerar en tupel av cellobjekt om det är en stängningsfunktion. Med hänvisning till exemplet ovan vet vi times3och times5är stängningsfunktioner.

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

Cellobjektet har attributet cell_innehåll som lagrar det slutna värdet.

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

Intressanta artiklar...