1.2 Variabelen en types
Een waarde bewaren onder een naam, en weten welke soort waarde het is
Na deze les kan je:
- de twee stappen van een toekenning in de juiste volgorde uitleggen
- voorspellen welke waarde een variabele bevat na een reeks toekenningen
- het type van een waarde bepalen en benoemen
- een waarde omzetten met
str(),int(),bool()enfloat(), en zeggen wanneer dat misloopt
De vorige les eindigde bij een programma dat alles onmiddellijk vergeet. Elke uitdrukking leverde een waarde op, en die waarde verdween zodra de volgende regel aan de beurt kwam. In deze les leer je een waarde bewaren onder een naam, zodat een latere regel er nog iets mee kan doen. Dat is de stap waarmee een programma iets kan opbouwen.
1 Waarom een programma moet onthouden
Stel dat je de rekening van een winkelmandje wil uitrekenen. Je kent de prijzen pas één voor één, en je wil het totaal zien wanneer het laatste artikel gepasseerd is. Met de middelen uit de vorige les lukt dat niet, aangezien elke uitdrukking haar waarde meteen weer kwijt is.
Een variabele lost dat op. Het is een stukje geheugen met een naam, waarin een programma een waarde bewaart om ze later terug te gebruiken.
Vanaf die regel duidt de naam leeftijd het getal \(17\) aan, en overal waar je leeftijd schrijft, staat er in feite dat getal.
2 Toekenning: eerst rechts, dan links
Het teken = heet een toekenning. De werking ervan ligt vast in twee stappen die altijd in deze volgorde gebeuren.
- Reken de uitdrukking rechts van het
=volledig uit. - Bewaar die uitkomst onder de naam links van het
=.
Het teken = is bijgevolg geen gelijkheidsteken. Het beweert niets, het geeft een opdracht, en die opdracht heeft een richting: van rechts naar links.
Een variabele houdt één waarde tegelijk vast. Een nieuwe toekenning overschrijft de vorige, en die vorige waarde is daarna nergens meer te vinden.
Wil je nagaan of twee zaken gelijk zijn, dan is = niet het teken dat je nodig hebt. Daarvoor bestaat ==, dat later aan bod komt.
3 De regel x = x + 1
In de wiskunde heeft de vergelijking \(x = x + 1\) geen enkele oplossing, want
\[ \{\, x \in \mathbb{R} \mid x = x + 1 \,\} = \emptyset . \]
Toch is x = x + 1 een volstrekt normale Python-regel. Dat komt doordat de twee stappen, de rechterkant uitrekenen en het resultaat toekennen aan de linkerkant, na elkaar gebeuren. Op het ogenblik dat de rechterkant uitgerekend wordt, heeft x nog zijn oude waarde.
Om zo’n reeks regels te volgen, schrijf je een trace table: één kolom per variabele, één rij per regel, en in elke rij wat de variabele op dat ogenblik bevat.
| regel | x |
|---|---|
x = 5 |
5 |
x = x + 1 |
6 |
De tweede rij gebruikt de waarde uit de eerste. Rechts staat dus \(5 + 1\), en de uitkomst \(6\) komt onder dezelfde naam terecht.
Deze constructie komt zo vaak voor dat Python er een afkorting voor heeft.
| voluit | afgekort |
|---|---|
x = x + 1 |
x += 1 |
totaal = totaal + prijs |
totaal += prijs |
Daarmee laat een programma een waarde aangroeien. Zo’n variabele heet een accumulator: ze begint bij een beginwaarde, en elke volgende regel voegt iets bij.
In een trace table is te zien dat elke regel verdergaat waar de vorige gestopt is.
| regel | totaal |
|---|---|
totaal = 0 |
0 |
totaal += 12 |
12 |
totaal += 5 |
17 |
totaal += 3 |
20 |
Het winkelmandje uit de eerste sectie is daarmee opgelost, zij het dat je voorlopig voor elk artikel een regel moet schrijven.
4 b = a neemt de waarde over
Twee namen kunnen dezelfde waarde aanduiden, en het is de moeite waard om na te gaan wat er dan met de tweede gebeurt wanneer de eerste verandert.
Er verschijnt 3. Met twee variabelen krijgt de trace table een kolom per naam, en dan is meteen te zien waarom.
| regel | a |
b |
|---|---|---|
a = 3 |
3 |
|
b = a |
3 |
3 |
a = 10 |
10 |
3 |
Bij b = a krijgt b de waarde die a op dat ogenblik heeft, en meer gebeurt er niet. Die regel is een gewone toekenning: rechts wordt de waarde van a opgezocht, en die uitkomst wordt toegekend aan b. Wat er daarna met a gebeurt, heeft geen effect op b.
5 Dezelfde bewerking, een andere uitkomst
Wat levert 2 + 2 op, en wat levert "2" + "2" op? Het enige verschil zijn de aanhalingstekens.
Er verschijnt 4, dan 22, dan hahaha. Het teken + telt getallen op en plakt teksten aan elkaar, en * vermenigvuldigt getallen en herhaalt een tekst. Wat een bewerking doet, hangt bijgevolg af van de soort waarden waarop ze werkt.
6 De vier types
De soort van een waarde heet haar type. Voorlopig volstaan er vier.
| type | waarvoor | voorbeelden |
|---|---|---|
int |
gehele getallen | 42, 0, -7 |
float |
kommagetallen | 2.4, -0.5, 3.14 |
str |
tekst, tussen aanhalingstekens | "hallo", "42", "" |
bool |
waar of onwaar | True, False |
Tekst tussen aanhalingstekens heet een string. 42 en "42" zien er op je scherm bijna hetzelfde uit: het eerste is een getal waarmee je kan rekenen, het tweede een tekstje dat toevallig uit cijfertekens bestaat.
Een bool heeft maar twee mogelijke waarden, True en False. Zo’n waarde is doorgaans het resultaat van een vergelijking, en de basis waarop een keuze wordt gemaakt.
Er verschijnt True, dan False. Een vergelijking levert dus een waarde op, net zoals een optelling dat doet.
De functie type() zegt je welk type een waarde heeft, wat nuttig is zodra je niet meer zeker bent van wat je in handen hebt.
Het antwoord komt in de vorm <class 'int'>.
De termen class en type stonden oorspronkelijk voor twee verschillende zaken. Python 3 heeft dat onderscheid opgeheven, en sindsdien zijn ze synoniem.
7 Wanneer Python weigert
Blijft de vraag wat er gebeurt wanneer je de twee soorten mengt. Levert 2 + "2" het getal 4 op, de tekst "22", of nog iets anders?
Python meldt een TypeError en stopt. Het weet niet of je \(4\) bedoelt of "22". Dat is beter zo, aangezien een taal die hier zomaar een keuze maakt, die keuze eveneens maakt op de plaatsen waar jij ze niet verwacht.
De foutmelding zelf is leesbaar: unsupported operand type(s) for +: 'int' and 'str' noemt de bewerking en de twee types die niet samengaan. Lees bij een vastgelopen programma altijd eerst het laatste regeltje van de melding.
8 Omzetten
Om van het ene type naar het andere te gaan bestaan er omzetfuncties. Ze geven een nieuwe waarde terug en laten de oude ongemoeid.
| omzetting | functie | voorbeeld |
|---|---|---|
| naar tekst | str() |
str(42) geeft "42" |
| naar geheel getal | int() |
int("42") geeft 42 |
| naar kommagetal | float() |
float("2.5") geeft 2.5 |
Daarmee is de gebruikelijke eerste struikelsteen opgelost, namelijk een getal aan een zin plakken.
int() werkt enkel op tekst die werkelijk een geheel getal voorstelt. int("3.5") loopt vast, en int("drie") eveneens. Daarnaast levert een deling met / altijd een float op, ook wanneer de uitkomst rond is, dus 10 / 2 geeft 5.0 en niet 5. Wil je een geheel getal overhouden, gebruik dan //.
9 Conclusie
Een variabele bewaart één waarde onder een naam, en een toekenning vult die waarde in. Eerst wordt de rechterkant uitgerekend, daarna wordt de uitkomst links bewaard. Doordat die twee stappen na elkaar komen, mag dezelfde naam aan beide kanten staan, en dat is precies wat een programma laat aangroeien.
Elke waarde die je zo bewaart, heeft bovendien een type, en dat type bepaalt wat een bewerking betekent. Hetzelfde teken + telt op of plakt aan elkaar, naargelang wat er links en rechts van staat, en waar de combinatie geen betekenis heeft, weigert Python te raden.
Wat je nu kan opschrijven, blijft evenwel even lang als het aantal stappen dat je wil zetten. Een mandje met twintig artikelen vergt twintig regels, en een teller die tot honderd loopt honderd. In een volgende les leer je hoe je zo’n reeks regels vervangt door twee.
10 Begrippen
- variabele (variable): een stukje geheugen met een naam, waarin een programma een waarde bewaart om ze later terug te gebruiken.
- toekenning (assignment): het bewaren van een waarde onder een naam met
=, in twee stappen: eerst de rechterkant uitrekenen, dan links bewaren. - overschrijven (to overwrite): een nieuwe toekenning aan dezelfde naam, waarbij de vorige waarde verdwijnt.
- trace table: een tabel met één kolom per variabele en één rij per regel, die laat zien wat elke variabele op dat ogenblik bevat.
+=(augmented assignment): de afkorting van een toekenning waarvan de rechterkant met de oude waarde begint.- accumulator: een variabele die een waarde stap na stap opbouwt, en die daarom vóór de eerste stap een beginwaarde krijgt.
- type (type): de soort van een waarde, die bepaalt wat een bewerking ermee doet.
- string (string): tekst tussen aanhalingstekens, in Python
str. - bool (boolean): het type met de twee waarden
TrueenFalse. - omzetfunctie (conversion function): een functie die een waarde van het ene type naar het andere brengt, zoals
str()enint().
11 Oefeningen
Een oefencel staat op zichzelf, dus wat je in een vorige cel schreef, kent Python hier niet meer.
Bepaal telkens wat er getoond wordt, zonder de computer. Maak bij de eerste een trace table.
p = 4, danp = p * p, danprint(p)n = 10, dann += 5, dann += 5, danprint(n)u = 2, danv = u + 3, danu = 100, danprint(v)"7" * 3enint("7") * 3"1" + 1print(type(3.5))enprint(type("3.5"))str(2) + str(2), en daarnaint("2.5") + 1k = 2, dank = k + k, dank += k, danprint(k)
TipAntwoorda.
16.regel pp = 44p = p * p16b.
20. Elke+=telt vijf bij de waarde van dat ogenblik, dus \(10\) wordt \(15\) en daarna \(20\).c.
5. Bijv = u + 3wordt de rechterkant uitgerekend met de waarde dieudan heeft, namelijk \(2\). De latere toekenning aanulaatvongemoeid.d.
"777"en21. In het eerste geval staat er een string die driemaal herhaald wordt. In het tweede levertint("7")het getal \(7\) op, waarna er gewoon vermenigvuldigd wordt.e. Een
TypeError. Er staat links tekst en rechts een getal, en Python kiest niet in jouw plaats. Bedoel je"11", schrijf dan"1" + str(1), en bedoel je \(2\), schrijf danint("1") + 1.f.
<class 'float'>en<class 'str'>. De aanhalingstekens maken het verschil, en het punt in"3.5"verandert daar niets aan.g.
"22"en eenValueError. Beide getallen worden eerst tekst, waarna+die twee aan elkaar plakt. In het tweede geval stelt"2.5"geen geheel getal voor, dus looptint()vast. Metfloat("2.5") + 1krijg je wel een uitkomst, namelijk3.5.h.
8. De twee schrijfwijzen doen hetzelfde, dus de waarde verdubbelt twee keer.regel kk = 22k = k + k4k += k8Vervang elke
______door code.Rechts van
+=mag een naam staan. Gebruik de twee namen die hierboven al een waarde gekregen hebben.Hieronder moet
xeerst verdubbeld worden en daarna met één verhoogd, elk op een eigen regel.Elke regel rekent eerst de rechterkant uit met de waarde die
xop dat ogenblik heeft. Na de eerste regel isxdus al veranderd.De twee waarden hieronder zijn strings. Zorg dat er
42verschijnt en niet1230.Zet beide waarden eerst om naar een geheel getal.
Toon met de twee namen hieronder de zin
3 boeken kosten 24 euro, zonder de getallen3en24zelf op te schrijven.Het totaal reken je uit met de twee namen. Alles wat in de zin terechtkomt, moet eerst tekst worden.
Verwissel de twee waarden hieronder, zodat er eerst
8verschijnt en daarna3. De twee regelsprintblijven staan zoals ze zijn.Zodra je
links = rechtsschrijft, is de oude waarde vanlinksnergens meer te vinden. Bewaar ze eerst onder een derde naam.
Verwissel dezelfde twee waarden opnieuw, maar nu met drie toekenningen en zonder een derde naam. Je mag enkel optellen en aftrekken.
Zet in
linkseerst de som van de twee. Uit die som en één van beide waarden haal je de andere terug.regel linksrechtslinks = 33rechts = 838links = links + rechts118rechts = links - rechts113links = links - rechts83De som blijft in
linksbewaard tot beide waarden er weer uit gehaald zijn.De regel hieronder is een geldige instructie. Python aanvaardt ze zonder één foutmelding. Wat is het resultaat, en waarom zou je zoiets zelf niet schrijven?
Twee regels die je nog niet kent en die je hier nodig hebt.
Een
booltelt in een berekening mee als een getal, waarbijTruevoor1staat enFalsevoor0.bool()van eender welke waarde isTrue, op0en de lege string""na. Enkel of er iets staat telt, niet wat er staat.Er verschijnt
4.0.stap uitkomst int(True)1bool("abc")True1 + True2float(2)2.02 + 2.04.0bool(7)True4.0 * True4.0Het is
4.0en niet4, aangezien één kommagetal in een berekening volstaat om de uitkomst een kommagetal te maken.Python weigert
2 + "2", maar tussen de getaltypes onderling is het erg meegaand, en dat is precies wat deze regel uitbuit. Dat ze aanvaard wordt, maakt er nog geen goede code van.bool("False")isTrue, aangezien enkel telt of er iets staat, en eenTruedie stilzwijgend als1meetelt, valt in een lange berekening niet meer op. Gebruikint()enfloat()waar je werkelijk van type verandert, en laatTrueenFalsestaan waar ze thuishoren, in een vergelijking.Nog zoiets: de Opgelet bij Omzetten zegt dat
int("3.5")vastloopt. Op het getal3.5werktint()wel, en dan valt alles na de komma weg, dusint(3.5)geeft3. Het verschil zijn de aanhalingstekens.