11B: De scope van een variabele

Les 11 kent drie delen A, B, C die in een willekeurige volgorde kunnen worden doorgewerkt.

In deze les leggen we het begrip scope (geldigheidsgebied) van een variabele uit. Het belangrijkste idee is, dat het mogelijk is om twee verschillende variabelen te hebben met dezelfde naam waarbij zij verschillende "scopes" hebben. Dit maakt het makkelijker om programma's te schijven en te verbeteren, in het bijzonder grote programma's.

Een voorbeeld van een "scope" van een programma

In dit voorbeeld is een deel van ons programma de volgende functie:

def square(x):
   value = x * x
   return value
Dit is de functie die het kwadraat van het getal x berekent, bijvoorbeeld square(5) geeft 25 als return waarde. Veronderstel dat we square aanroepen vanuit een ander deel van het programma waarin een value variabele voor een ander doel wordt gebruikt

# hier begint het hoofdprogramma
value = 17
fivesquared = square(5)
print(fivesquared, value)
De vraag is wat er in dit scenario zal worden afgedrukt? Er zijn twee mogelijkheden, wanneer we niet weten hoe Python werkt:

  1. Een mogelijkheid is dat Python herkent dat de twee value variabelen op de een of andere manier "gescheiden moeten worden" . Dus, de aanroep van square zal 25 teruggeven, maar de waarde van value in het hoofdprogramma blijft 17, en we zien als uitvoer afgedrukt worden 25 17.
  2. De andere mogelijkheid bestaat eruit dat bij het uitvoeren van square, het de bestaande waarde van value overschrijft met 25, en we als uitvoer afgedrukt worden 25 25.

Laten we nagaan wat er daadwerkelijk gebeurt!

We zien dat het gedrag van Python overeenkomt met de beschrijving in mogelijkheid nr 1. Het is zo, wanneer je een functie aanroept, kun je geen variabelen bewerken die buiten de functie zijn gedefinieerd. In plaats daarvan zullen alle opdrachten die waarden toekennen aan een "lokale" variabele die zich bevindt "binnen" de aangeroepen functie. De reden dat Python, en de meeste andere talen dat doen, is dat het daardoor veel gemakkelijker is grote programma's te schrijven met vele functies. In het bijzonder is het daardoor mogelijk een nieuwe functie te schrijven en daarin elke willekeurige variabele naam te gebruiken (inclusief de gewone zoals result, temp en i) zelfs wanneer zij elders voor andere doelen zijn gebruikt.

Kijk naar "step 6 van 8" hierboven. Merk op dat er twee verschillende variabele zijn met de naam value: een binnen de functie square, en een daarbuiten ( het "globale" gedeelte).

Meerkeuze Opgave: Erbinnen en erbuiten
Wat is de output van het volgende programma?

x = "erbuiten"
def xReplace(value):
  x = value
xReplace("erbinnen")
print(x)
Correct! Het statement x = value verandert alleen de lokale versie van variabele x in de functie. De globale x verandert niet (En de functie xReplace is dus nutteloos en verandert nooit iets).

Een vergelijkbaar concept als een scope is een namespace; een namespace is een soort scope voor een package. Dus als je een package importeert (zoals bijvoorbeeld math) overlapt dit niet met de variabele x in je eigen programma, omdat ze verschillende namespaces hebben.

Regels voor scopes: globaal en lokaal

Er zijn situaties waarin we variabelen van globale en lokale scope door elkaar willen gebruiken. Een voorbeeldje is als je een bepaalde variabele eenmalig een waarde wil geven aan het begin van het programma, maar je wil deze variabele nog wel gebruiken in de rest van je programma.

Voorbeeld
Een globale functie binnen een functie uitlezen

De lokale scope bevat hier geen variabele genaamd favourietePizza, maar dit leidt niet tot een foutmelding. Wanneer Python een variabele in de lokale scope niet kan vinden wordt gekeken of er in de globale scope wel een variabele met die naam bestaat. In dit geval wordt favourietePizza inderdaad in de globale scope gevonden.

In de bovenstaande voorbeelden zijn bestelPizzas en xReplace syntactisch bijna helemaal identiek. Waarom maakt Python een lokale variabele x in xReplace, maar geen nieuwe favorietePizza in bestelPizzas? De regel in Python is als volgt: als je alleen leest uit de variabele wordt er geen nieuwe lokale variabele gemaakt; schrijf je echter ergens in de functie naar de variabele, dan wordt deze variabele in de hele functie als lokaal beschouwd. (Dit is de meest voorkomende oorzaak van de foutmelding UnboundLocalError: zie ook [1, 2] in de officiële Python-documentatie.)

Functie-argumenten worden altijd als lokale variabelen beschouwd:

Het gebruik van global

Zoals zo vaak werkt bovenstaande aanpak in 99% van de gevallen. Er zijn echter gevallen te bedenken waar je echt de waarde van een globale variabele wilt veranderen binnen een functie. Python stelt je in staat dit te doen door middel van het global statement. Hieronder staat een aangepaste versie van het eerdere xReplace-voorbeeld.

Zoals we eerder besproken vereist lezen van een variabele niet dat je global gebruikt; dit is alleen nodig als je wilt schrijven.

Je hebt deze les nu afgerond en kun je door naar de volgende.