ProgrammatiePython-ontwikkelaar

Hoe werken closures in Python? Wat zijn de bijzonderheden van de toegang tot variabelen van de externe functie, en hoe kunnen we valkuilen vermijden die verband houden met de mutabiliteit van variabelen?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

Closures zijn een krachtig mechanisme in Python dat het mogelijk maakt om functies te creëren met "onthouden" gegevens uit de omringende context.

Achtergrond van de vraag

In functionele talen en in Python zijn functies eerste-klassobjekten. Een functie kan een nieuwe functie retourneren die variabelen uit zijn omringende (externe) scope "sluit".

Probleem

Ontwikkelaars raken vaak in de war over hoe precies gesloten variabelen "leven" binnen een closure, wanneer ze worden gelezen of geschreven, en hoe ze veilig mee om moeten gaan (vooral met mutabele objecten).

Oplossing

Als de interne functie variabelen van de externe functie gebruikt, worden deze automatisch "onthouden" — zelfs als de externe functie al is afgelopen. Voor het lezen van een variabele is dit duidelijk, maar als je de waarde wilt wijzigen, moet je het sleutelwoord nonlocal gebruiken. Bij het werken met mutabele objecten (lijsten, dicts) is dit een bijzondere risicosituatie.

Voorbeeld:

def outer(): count = 0 def inner(): nonlocal count count += 1 return count return inner counter = outer() print(counter()) # 1 print(counter()) # 2

Belangrijkste kenmerken:

  • De geneste functie onthoudt de waarden van de variabelen die in scope waren op het moment van zijn creatie.
  • Gebruik nonlocal voor het wijzigen van gesloten variabelen (anders creëert de bewerking een lokale variabele).
  • Verwijzingen naar objecten in de closure blijven behouden, zelfs na het verlaten van de externe functie, wat het mogelijk maakt om functiefabrieken, lexicale tellers en veel meer te implementeren.

Misleidende vragen.

Is het mogelijk om de waarde van een gesloten variabele binnen een functie te wijzigen zonder nonlocal?

Nee. Als je probeert een nieuwe waarde toe te wijzen zonder nonlocal te vermelden, beschouwt Python dit als het creëren van een nieuwe lokale variabele, en de oude waarde zal niet naar buiten komen.

Voorbeeld:

def make_counter(): count = 0 def inner(): count += 1 # OnboundLocalError! return count return inner

Is het mogelijk om argumenten naar de externe scope door te geven via closure?

Ja, de closure "onthoudt" alle variabelen die beschikbaar zijn in de externe scope, inclusief klasse-attributen, globale variabelen, enz. Maar het wijzigen van deze variabelen vereist bijzondere inspanningen (bijvoorbeeld het gebruik van nonlocal of global).

Wat gebeurt er met mutabele objecten binnen een closure?

Als een closed variabele een verwijzing naar een mutabel object, bijvoorbeeld een lijst, bevat, kun je de inhoud ervan zonder nonlocal wijzigen, maar als je probeert de variabele opnieuw te verwijzen, is nonlocal vereist.

Voorbeeld:

def make_appender(): result = [] def append(x): result.append(x) # Kan! return result return append f = make_appender() print(f(1)) # [1] print(f(2)) # [1, 2]

Typische fouten en anti-patronen

  • Probeer een variabele in de closure opnieuw toe te wijzen zonder nonlocal.
  • Gebruik closure voor het opslaan van mutabele toestand, zonder de mogelijke geheugenlekken te realiseren.
  • Moeilijk leesbare code door een te groot aantal gesloten variabelen.

Voorbeeld uit het leven

Negatieve case

Een ontwikkelaar schrijft een closure en wijzigt een variabele zonder nonlocal — dit leidt tot een UnboundLocalError.

Voordelen:

  • Snelle prototyping van tellers, fabrieken.

Nadelen:

  • Onvoorspelbaar gedrag, bugs bij het vergeten van nonlocal.

Positieve case

Expliciet gebruik van nonlocal voor beheerde toestand in de closure.

Voordelen:

  • Duidelijk controleerbare toestand, gemakkelijk om tellers en functiefabrieken te implementeren.

Nadelen:

  • Moeilijker te begrijpen en te debuggen bij grote ketens van closures.