CoderDojo Dendermonde voor CoderDojo-kids CoderDojo Dendermonde - voorjaar 2015 Inhoud [1] Wat is Python? [2] Aan de slag [3] Kennismaken met IDLE [4] Enkele eenvoudige commando’s om mee aan de slag te gaan [5] Verschillen en gelijkenissen met Scratch en RoboMind [6] Zakwoordenboekje Python-Engels ↔ Nederlands [7] Variabelen en constanten [8] De ene 1 is de andere niet [9] Rekenen met Python [10] Werken met tekst (strings) [11] Beslissingen nemen [12] Tupels, lijsten en woordenboeken [13] Rondjes draaien (loops) [14] Functies [15] Variabelen in functies (of: een woordje over scope) [16] In Python ingebouwde functies (in voorbereiding) [17] Fouten vinden en oplossen (in voorbereiding) [18] Bibliotheken (in voorbereiding) [19] Klasses en objecten (in voorbereiding) [20] Werken met bestanden (in voorbereiding) [21] Traaaaaaaaag tekenen met turtle (in voorbereiding) [22] Beter tekenen met tkinter (in voorbereiding) [23] Spellen ontwikkelen met PyGame (in voorbereiding) [P1] Project: Raad een getal [P2] Project: Gekke zinnen [P3] Project: Tekenmachine [P4] Project: De P-taal [P5] Project: Bellenschieter [P6] Project: Kleurbollen (in voorbereiding) [P7] Project: Botsbal (in voorbereiding) [P8] Project: Stokjesman (in voorbereiding) Python voor CoderDojo kids versie 9/03/2015 [1] Wat is Python? (onderstaande tekst is geïnspireerd door het Python-artikel op Wikipedia) We zijn binnen CoderDojo nu al een tijdje bezig met Scratch en RoboMind. Scratch leert je de beginselen van programmeren op een visuele manier (via het slepen met blokken), en bij RoboMind hebben we de stap gezet naar programmeren in tekst-code. Maar de programmeertaal die bij RoboMind gebruikt wordt is geen echte programmeertaal. Daarom zetten we nu de stap naar Python, een wereldwijd gebruikte programmeertaal. De bekendste gebruiker van Python is Google – heel veel van de code van hun webtoepassingen (zoals de gewone Google Zoeken) is geschreven in Python. Python is een open source programmeertaal die begin jaren ‘90 ontworpen en ontwikkeld werd door Guido van Rossum, destijds verbonden aan het Centrum voor Wiskunde en Informatica in Amsterdam. Inmiddels wordt de taal doorontwikkeld door een enthousiaste groep, geleid door Van Rossum, recent nog werkzaam bij Google, maar nu in dienst van Dropbox. Deze groep wordt ondersteund door vrijwilligers op het internet. De ontwikkeling van Python wordt geleid door de Python Software Foundation. Python heeft zijn naam te danken aan het favoriete televisieprogramma van Guido van Rossum, Monty Python. Python is een heel makkelijk aan te leren taal, omdat er geen ingewikkelde commando’s gebruikt worden, en omdat het gebruik van indentatie verplicht is in Python. Dat wil zeggen dat je elk commando op een nieuwe regel moet zetten, en dat je blokken code moet laten inspringen. Hierdoor is het een uiterst leesbare taal. In PHP bijvoorbeeld – dat is een andere populaire programmeertaal – is het gebruik van indentatie niet verplicht. Daar kan een if-then-else er als volgt uit zien: if ($voorwaarde) { echo "Voorwaarde voldaan"; $teller++; } else { echo "Voorwaarde niet voldaan"; } In Python ziet dezelfde if-then-else er verplicht zo uit: if voorwaarde == True: print('Voorwaarde voldaan') teller += 1 else: print('Voorwaarde niet voldaan') Door deze inspringing en nog een aantal andere elementen is Python uitermate geschikt om programmeerstructuren uit te leggen. Python is een zuivere taal met weinig uitzonderingen. Het is voor alle gebruik gratis op het internet te krijgen en werkt op verschillende types computers. Python kan ook gebruikt worden om webapplicaties te ontwikkelen. Python [1] Wat is Python? versie 12/03/2015 1/1 [2] Aan de slag Webpagina’s CoderDojo Dendermonde Alle informatie over Python @ CoderDojo Dendermonde vind je op dendermonde.coderdojobelgium.be/python Je vindt er ook deze leerfiches in PDF-formaat, en je kan er de oefenbestanden downloaden. Ook de andere nuttige links (zoals waar je Python kan downloaden) vind je op deze infopagina’s. Heb je opmerkingen of suggesties? Geef ons dan een seintje op [email protected]. Oefenbestanden Wie graag met papieren naast zijn computer werkt, kan de leerfiches volledig doorlopen op papier. Alle info staat op de blaadjes, en je kan alle code intypen om een werkend programma te krijgen. Je kan er ook voor kiezen om de fiches te volgen met hulp van de Python-bestanden op het web. Als je op onze webpagina de oefenbestanden downloadt en opent in de Python-ontwikkelomgeving IDLE, dan krijg je de meeste voorbeeldprogramma’s, voorzien van enige commentaar. De meeste leerfiches leren je een nieuw concept en bevatten dus behoorlijk wat theorie. Maar er zijn ook een aantal leerfiches (aangeduid met een ‘P’ vooraan) die projecten bevatten. Bij die projecten ligt de nadruk meer op experimenteren met code dan op de theorie achter Python. Bij elk project staat aangegeven welke leerfiches je best al even doorgenomen hebt. Python installeren Python is een gratis programmeeromgeving. Alle info over Python en de Python Software Foundation vind je op de officiële website www.python.org Op www.python.org/downloads kan je de laatste versie downloaden. Let op, je krijgt de keuze tussen Python 2 en Python 3. In deze leerfiches wordt uitsluitend met Python 3 gewerkt. Kies dus de juiste versie. Op het moment dat we deze leerfiches maken is de laatste versie 3.4.2 Voer de installer uit, en klik “Volgende” tot de installatie loopt en uiteindelijk beëindigd is. Je start de Python-ontwikkelomgeving op via het programma IDLE. Python [2] Aan de slag versie 12/03/2015 1/2 De IDLE-omgeving start op, en je krijgt de lege Python-shell voor je neus. Meer uitleg over de IDLE-omgeving vind je in leerfiche [3] “Kennismaken met IDLE”. Je eerste programma Er is een heilige regel in het land van de programmeertalen dat het eerste programma dat je aanleert in een nieuwe taal het zogenaamde “Hello World” programma moet zijn. Kijk het maar eens na in de bibliotheek: zowat élk boek dat je een programmeertaal aanleert zal beginnen met aanleren hoe je “Hello world!” op het scherm kan laten verschijnen. We willen de programmeergoden niet ongunstig stemmen, en we gaan dus vooral braafjes datzelfde regeltje volgen. We willen ons niet voorstellen wat er zou gebeuren als we de heilige regel zouden breken! Maar we geven er wel onze eigen draai aan. Hier komt “Hallo Dendermonde” in Python. Let op, want voor je het weet is het voorbij. Je hebt in de vorige stap de IDLE-omgeving geïnstalleerd en gestart. Als alles goed gaat staat de Python Shell nu voor je neus. De Python Shell toont een prompt (>>>) waar je commando’s kan intypen. Als je hier een commando intikt en entert, wordt het direct uitgevoerd. Ben je er helemaal klaar voor? Tik dan nu volgende regel letterlijk in, en druk op enter. print('Hallo Dendermonde!') Het wonder geschiedt! Direct eronder verschijnt “Hallo Dendermonde!” Zo! Je hebt je eerste programma in Python geschreven! Beetje teleurgesteld dat het maar dit was?? Geen nood, we gaan echt wel nog straffere dingen doen. :-) Python [2] Aan de slag versie 12/03/2015 2/2 Meer weten? Omdat Python een gratis (open source) taal is die heel populair is en veel gebruikt wordt, is er heel veel informatie over Python terug te vinden op internet. We geven jullie de interessantste referenties graag mee. Boeken o Programmeren voor kinderen – Carol Vorderman – uitgegeven bij Lannoo www.lannoo.be/programmeren-voor-kinderen o Python for kids (Engelstalig) – Jason R. Briggs www.amazon.com/Python-Kids-Playful-Introduction-Programming/dp/1593274076 o Invent Your Own Computer Games With Python (Engelstalig) – Al Sweigart Making Games With Python & PyGame (Engelstalig) – Al Sweigart www.inventwithpython.com o Hello World! Computer Programming for Kids and Other Beginners – Warren Sande www.amazon.com/Hello-World-Computer-Programming-Beginners/dp/1617290920 Websites o Python website (Engelstalig) www.python.org/doc o Leren programmeren in Python www.win.tue.nl/~wstomv/edu/python/python1.html o Programmeren voor kinderen programmerenvoorkinderen.nicolaas.net o Codecademy (Engelstalig) www.codecademy.com/tracks/python o Invent with Python (Engelstalig) www.inventwithpython.com o A beginner’s Python Tutorial http://www.sthurlow.com/python/ Python online uitproberen (zonder installatie) o repl.it/languages/Python3 Aanvullingen en suggesties Deze leerfiches werden samengesteld door Karel Titeca in het voorjaar van 2015 voor CoderDojo Dendermonde. Heb je een opmerking, een aanvulling, een suggestie, of heb je ergens een foutje gevonden? Dan horen we het graag van je. Geef gerust een seintje op [email protected]. Python [2] Aan de slag versie 12/03/2015 3/3 [3] Kennismaken met IDLE In leerfiche [2] hebben we Python geïnstalleerd, met de IDLE-ontwikkelomgeving, en hebben we ons eerste programma geschreven. Nu is het tijd om die omgeving wat te leren kennen. Het Shell-venster versus het Code-venster Als we IDLE opstarten verschijnt het Shell-venster. Zoals we bij onze “Hallo Dendermonde” gemerkt hebben wordt code die in het Shell-venster ingetypt wordt, direct uitgevoerd. Dat is handig om dingetjes te testen, maar dat is natuurlijk niet zo handig om een volledig programma te schrijven. Om een nieuw programma te beginnen, open je een leeg nieuw venster via File > New. Een nieuw, leeg venster verschijnt, en als je hier code intypt wordt deze niet direct uitgevoerd. Om de code uit te voeren moet je het programma dat je net gemaakt hebt eerst opslaan (via File > Save As…) en het vervolgens uitvoeren via Run > Run Module, of via de sneltoets F5. Python [3] Kennismaken met IDLE versie 12/03/2015 1/3 Als voorbeeldprogramma kan je bv. onderstaand programma gebruiken: wereld = 'Dendermonde' print('Hallo', wereld) Zodra je dit programma opslaat en uitvoert, verschijnt er “Hallo Dendermonde” in het Shell-venster. De uitvoer van een programma verschijnt dus in het Shell-venster. Vuistregel: code uitproberen doe je in het Shell-venster, programma’s schrijven doe je in een apart venster. Programmeerhulp en kleuren in de code De code van een Python-programma bestaat eigenlijk alleen maar uit tekst. Dus het maakt niet uit of je je code schrijft in Kladblok, in een andere tekst-editor of in de IDLE-programmeerinterface. Maar één van de grote voordelen van programmeren in een IDE (Integrated Development Environment – geïntegreerde ontwikkelomgeving) is dat je als programmeur geholpen wordt bij het schrijven van je programma. Deze hulp komt er op een aantal manieren: Je krijgt tooltips die je info geven over de functie die je probeert te gebruiken. De code verschijnt in kleur, zodat je gemakkelijker de commando’s van de variabelen kan onderscheiden. Zo’n gekleurde code is heel handig. Neem nu bv. volgend Python-programma: # Dit programma telt gehele getallen op de commandolijn op import sys try: total = sum(int(arg) for arg in sys.argv[1:]) print('sum =', total) except ValueError: print 'Gelieve gehele getallen op te geven' De verplichte indentatie zorgt er voor dat het programma al vrij vlot leesbaar is. Maar het is moeilijk om de verschillende onderdelen van het programma uit elkaar te houden. Bekijken we hetzelfde programma nu eens mét kleuren in de code, dan zien we direct wat de commando’s zijn, wat de variabelen zijn en wat de strings zijn. # Dit programma telt gehele getallen op de commandolijn op import sys try: total = sum(int(arg) for arg in sys.argv[1:]) print('sum =', total) except ValueError: print 'Gelieve gehele getallen op te geven' Python [3] Kennismaken met IDLE versie 12/03/2015 2/3 Om praktische redenen kunnen we in deze leerfiches niet dezelfde kleurencodering aanhouden als in de Python IDLE. In de IDLE ziet dezelfde code er als volgt uit: De kleuren duiden het volgende aan: rood: commentaar (grijs in deze cursustekst) oranje: Python-kerncommando’s (donker oranje in deze cursustekst) paars: Python-functies (donker oranje in deze cursustekst) groen: strings (teksten) (donkerblauw in deze cursustekst) zwart: variabelen, rest Commentaar Programmeurs moeten soms creatief zijn om met programmacode een bepaald probleem op te lossen. En dus hebben ze soms wel eens een geniale inval terwijl ze aan het programmeren zijn, om een probleem op een heel specifieke manier op te lossen. Het enige probleem is: soms snappen ze een paar maand later zelf niet meer wat ze geschreven hebben als ze hun code opnieuw openen. Laat staan dat iemand anders het snapt! Het is belangrijk dat code leesbaar is. Want programma’s worden voortdurend aangepast, en soms zal je dus na meer dan een jaar een programma opnieuw openen, en hoe leesbaarder je code is, hoe sneller je zal kunnen foutloos aanpassingen doen. Python helpt ons om de code leesbaar te maken door zijn simpele syntax (dat is de set van commando’s en de schrijfwijze van die commando’s) en door het verplichte inspringen van de code. Maar toch blijft het nodig om commentaar te schrijven in onze code, om uitleg te geven bij wat we doen. Je hebt vast al gezien hoe we commentaar schrijven in de voorbeeldjes: met een spoorwegtekentje (#). Als er op een regel zo’n # staat, dan wordt alles erachter volledig genegeerd. Dus je kan zo’n tekentje zetten aan het begin van een regel, of je kan het vlak na een commando zetten. naam = 'Karel' # Dit kan ook een andere naam zijn # Nu gaan we de naam op het scherm laten verschijnen: print('Hallo ik ben', naam) Python [3] Kennismaken met IDLE versie 12/03/2015 3/3 Je kan ook hele blokken commentaar maken door een blok te beginnen met ''' en door het weer te eindigen met ''' (drie quote-tekentjes). ''' Dit is een blokje commentaar. Ik hoef dus geen #-tekentjes voor elke regel te zetten. ''' print('Dit is geen commentaar meer') In de volgende leerfiche maken jullie kennis met het spokenspel. Bekijk de code van het spokenspel goed – deze is overvloedig voorzien van commentaar. Nog even dit: geen enkele programmeur vindt het leuk om zijn code van commentaar te voorzien. Documentatie schrijven vindt een programmeur niet fijn. Maar toch is het heel belangrijk om dit altijd te doen. Je zal jezelf dankbaar zijn als je je eigen code opnieuw bekijkt, en je zal je vrienden dankbaar zijn als je hun code bekijkt. Oefeningen Oefen op het verschil tussen het Shell-venster en het codevenster. Schrijf enkele regeltjes code in het Shell-venster, en kijk wat ze doen. Schrijf een programma in het codevenster, sla het op en voer het uit. Probeer ook een stukje van je programma in commentaar te zetten. Python [3] Kennismaken met IDLE versie 12/03/2015 4/4 [4] Enkele eenvoudige commando’s om mee aan de slag te gaan Tijd om aan de slag te gaan! We gaan er het eerste oefenbestand bij nemen, en enkele commando’s intypen. Volg mee via 04_EnkeleCommandos.py Als je het bestand opent in de IDLE-editeeromgeving, dan krijg je volgende code te zien: # Tijd om enkele eenvoudige commando's aan te leren om mee aan de slag te gaan # print kennen we al. Daarmee laten we een regel op het scherm zien. print("Dit is een regel die op het scherm verschijnt") # Je mag kiezen # gebruikt rond print('Dit zijn print("Dit zijn of je 'enkele quotes' of "dubbele quotes" een tekst. We proberen zoveel mogelijk voor de 'enkele' te gaan enkele quotes') dubbele quotes") # Als je ooit zo'n quote in een tekst wil gebruiken, kan je deze "escapen" # door er een backslash (\) voor te zetten print('Dit is zo\'n geval waarbij ik zo\'n backslash nodig heb') # We gaan later nog veel leren over variabelen, maar deze eenvoudige vorm snap # je vast wel: programmeertaal = 'Python' print('Hoera, ik leer', programmeertaal) # Met 'input' kunnen we de gebruiker zelf een variabele laten ingeven. # Probeer maar eens: naam = input('Hoe heet jij? ') print('Aangenaam,', naam, '!') # Tot slot tonen we nog even een herhaling: for getal in range(1, 10): # getal is de eerste keer 1, de volgende keer 2, ... # en elke keer wordt de lus herhaald, tot getal 10 is # als getal 10 is wordt de lus direct gestopt. # 10 verschijnt dus niet meer print('Ik kan al tellen tot', getal) Voer het programma maar eens uit (F5) en bekijk wat er gebeurt. Bekijk nu de code. Welke commando’s zien we zoal? print: om een regel op het scherm te laten zien = om een inhoud aan een variabele toe te kennen input om iets van de gebruiker te vragen for om een lus te maken Python [4] Enkele eenvoudige commando’s om mee aan de slag te gaan versie 12/03/2015 1/2 Het spokenspel (sterk geïnspireerd door het boek “Programmeren voor kinderen”) Okee, tijd voor een iets moeilijker programma. Het spokenspel. Sorry, er komen geen leuke tekeningetjes bij kijken – je moet je fantasie gebruiken. We bevinden ons in een spookhuis, en we lopen door een reeks kamers. In elke kamer zijn er 3 deuren. Aan jou om de juiste deur te kiezen: achter 1 deur zit een spook, de 2 andere deuren zijn veilig. Hoeveel kamers kan je doorlopen voor een spook je te pakken krijgt? Volg mee via 04_Spokenspel.py Open het spel, en voer de code uit. Mijn high score was 24. Hoeveel haal jij? Dit is de code van het spel: # Spokenspel from random import randint # Hiermee importeren we de functie 'randint', waarmee we # willekeurige getallen kunnen laten kiezen door de computer print('Spokenspel') print('----------') # --- VARIABELEN --ik_ben_dapper = True score = 0 # De titel verschijnt # Hiermee houden we bij of we nog verder durven gaan # Onze beginscore. while ik_ben_dapper: # De regeltjes hieronder worden uitgevoerd zolang ik dapper ben spokendeur = randint(1,3) # De computer kiest een deur print('Er zijn drie deuren.') print('Er zit een spook achter een van de deuren.') print('Welke deur wil je openen?') gekozendeur = input('Deur 1, 2 of 3? ') # We vragen een keuze deurnummer = int(gekozendeur) # Wat ingetypt is wordt omgezet # naar een getal if deurnummer == spokendeur: print('SPOOK!!!') ik_ben_dapper = False # Als er een spook is, stopt het spel else: print('Geen spook!') print('Je mag door naar de volgende kamer.') print('\n') # Een lege regel score = score + 1 # Onderstaande regels worden pas uitgevoerd als het spel voorbij is print('Loop weg!!!!') print('Spel voorbij! Je score is:', score) Python [4] Enkele eenvoudige commando’s om mee aan de slag te gaan versie 12/03/2015 2/2 Bekijk de code aandachtig. Er staat heel wat commentaar tussen de code die uitlegt wat er allemaal gebeurt. Zit er niet mee in als je de code nog niet helemaal snapt. Dat komt nog wel! Ben je niet zeker wat iets doet? Experimenteer dan! Verander iets in de code, en kijk wat er gebeurt. Zo leer je makkelijk bij! Maak je een foutje? Geen probleem! Python zal je hier via een hoop rode tekst op attent maken. En dan is het speuren geblazen om de fout te vinden. :-) Veel plezier! Oefeningen Experimenteer met het spokenspel. Verander zaken in de code en kijk wat er gebeurt. Schrijf ook een eigen programma waarin je de naam vraagt van de speler, en vervolgens “Hallo” op het scherm laat verschijnen, gevolgd door de naam. Schrijf een programma dat een willekeurig getal tussen 50 en 100 op het scherm laat verschijnen. Python [4] Enkele eenvoudige commando’s om mee aan de slag te gaan versie 12/03/2015 3/3 [5] Verschillen en gelijkenissen met Scratch en RoboMind (deze leerfiche is grotendeels overgenomen uit het boek “Programmeren voor kinderen” van Carol Vorderman) Op het eerste gezicht kan Python je misschien afschrikken, vooral als je het vergelijkt met Scratch. De twee talen verschillen echter niet zo veel van elkaar als het lijkt. In onderstaande tabel zie je een overzicht van de overeenkomsten tussen de basiscommando’s in Python, Scratch en RoboMind. Zit er niet mee in als je nog niet alles snapt – dat komt nog wel! Commando Python 3 Scratch 2 Start Programma Menu ‘Run’ of druk op F5 Uitvoeren (F5) Stop programma Druk op Ctrl+C in het Shellvenster Uitvoeren > Stop (Esc) Schrijf tekst naar scherm print(‘Hallo!’) - Link een variabele aan een getal magischNummer = 5 - Link een variabele aan een tekststring woord = ‘draak’ - Lees tekst van toetsenbord in variabele leeftijd = input(‘Leeftijd?’) print(‘Ik ben %s jaar’ % leeftijd) - Voeg een getal toe aan een variabele katten = katten + 1 of katten += 1 - Optellen a + 2 - Aftrekken a – 2 - Vermenigvuldigen a * 2 - Delen a / 2 - Eeuwige lus while True: spring() herhaal { vooruit(1) } Herhaal 10 keer for i in range(10): spring() herhaal(10) { vooruit(2) rechts } Is gelijk aan? a == 2 - Python [5] Verschillen en gelijkenissen met Scratch en RoboMind RoboMind versie 12/03/2015 1/2 Commando Python 3 Scratch 2 Is minder dan? a < 2 - Is meer dan? a > 5 - NIET not niet OF or of EN and en als … dan if a == 2: print('Hallo!') als(linksIsWit) { links vooruit(1) verfWit stopVerven achteruit(1) rechts } als … dan … anders if a == 2: print('Hallo!') else: print('Daaaaag!') als(linksIsWit) { vooruit(1) } anders { achteruit(1) } Lus met voorwaarden while rol != 6: spring herhaalZolang(voorIsObstakel) { vooruit(1) } Wacht from time import sleep sleep(2) - Willekeurige getallen from random import randint rol = randint(1, 6) - Definieer een functie of een subprogramma def spring(): print('Spring!') procedure schilder() { verfWit } Roep een functie of een subprogramma aan spring() schilder() Definieer een functie of een subprogramma met invoer def begroet(wie): print('Hallo', wie) procedure schilderStap(aantal) { herhaal(aantal) { verfWit vooruit(1) } } Python [5] Verschillen en gelijkenissen met Scratch en RoboMind RoboMind versie 12/03/2015 2/2 Commando Python 3 Scratch 2 RoboMind Roep een functie of subprogramma met invoer begroet('Iljo') schilderStap(5) Tekenen from turtle import * clear() pendown() forward(100) right(90) penup() verfWit() vooruit(100) rechts(90) stopVerven() Strings aan elkaar hangen print(begroeting + naam) - Een letter uit een string oproepen naam[0] - Lengte van een string len(naam) - Maak een lege lijst menu = list() - Voeg een item toe aan einde lijst menu.append(ding) - Hoeveel items op lijst? len(menu) - Waarde van 5de item op lijst menu[4] (zie opmerking hieronder) - Verwijder 2de item van lijst del menu[1] - Staat item op lijst? if 'spruitjes' in menu: print('Oh nee!!!') - (Opmerking: we hebben geen fout gemaakt in de bovenstaande tabel door bij “Waarde van 5de item op lijst” menu[4] te zetten. De uitleg daarvoor volgt later, als we het over lijsten hebben.) Oefening Open één van je bestaande (eenvoudige) Scratch-scripts. Bekijk de code. Kan je een poging doen om de code van één enkele sprite om te zetten naar Python? Python [5] Verschillen en gelijkenissen met Scratch en RoboMind versie 12/03/2015 3/3 [6] Zakwoordenboekje Python-Engels ↔ Nederlands Ongeveer elke programmeertaal is in het Engels. Er bestaan enkele pseudo-programmeertalen die vertaald worden in verschillende talen (de RoboMind-programmeertaal is beschikbaar in het Nederlands bijvoorbeeld, of de Scratch-commando’s zijn ook vertaald), maar met echte programmeertalen wordt dat over het algemeen nooit gedaan. We zullen dus nooit C-code, PHP-code, JavaScript-code of Python-code in het Nederlands schrijven, maar altijd in het Engels. Dat lijkt moeilijker dan het is. Als je enkele commando’s kent in het Engels, ben je hier snel mee vertrokken. Als je bv. weet dat ‘if’ Engels is voor ‘als’ en ‘else’ Engels is voor ‘anders’, heb je zo je eerste als-dan-anderslus geschreven. Om elk commando goed te begrijpen krijg je van ons een klein zakwoordenboekje met de meest voorkomende commando’s in Python, en wat ze betekenen in het Nederlands. Python-commando Nederlandse vertaling and / or / not en / of / niet append voeg toe break breek af class klasse clear wis continue ga verder met de volgende lus count tel def definieer (functie) dict (= dictionary) woordenboek extend breid uit for voor elke from … import * importeer alle commando’s uit bibliotheek … if … elif … else als … anders-als … anders import importeer bibliotheek index volgnummer input vraag invoer van gebruiker print laat een regel op het scherm verschijnen Python [6] Zakwoordenboekje Python-Engels ↔ Nederlands versie 12/03/2015 1/1 Python-commando Nederlandse vertaling range reeks return … geef … terug reverse draai om sort sorteer sorted gesorteerd True / False waar / onwaar while terwijl Python [6] Zakwoordenboekje Python-Engels ↔ Nederlands versie 12/03/2015 2/2 [7] Variabelen en constanten We gaan een eenvoudig programma schrijven waarbij we reclame maken voor CoderDojo Dendermonde. Volg mee via 07_VariabelenConstanten.py Dit is wat er moet verschijnen op het scherm op het einde van het programma: We verwachten je bij CoderDojo Dendermonde! De volgende sessie gaat door op zaterdag 4 april in de jeugddienst aan de achterkant van de bib (Dendermonde). We verwachten 36 kids van 7 tot 16 jaar (dat zijn 10 verschillende leeftijden!) Afspraak om 10 uur! Natuurlijk is dit een fluitje van een cent als we gewoon de 5 bovenstaande regels via een print-commando op het scherm laten verschijnen. Maar zo makkelijk gaan we ons er niet van af maken! Als we gewoon de 5 regeltjes tekst in een programma zouden steken, zouden we ons programma elke keer moeten aanpassen als er een nieuwe sessie is. Laten we even op zoek gaan naar de elementen in de tekst die mogelijk kunnen veranderen, en hoe waarschijnlijk het is dat ze veranderen: We verwachten je bij CoderDojo Dendermonde! De volgende sessie gaat door op zaterdag 4 april in de jeugddienst aan de achterkant van de bib (Dendermonde). We verwachten 36 kids van 7 tot 16 jaar (dat zijn 10 verschillende leeftijden!) Afspraak om 10 uur! Een aantal elementen is in het rood aangeduid. Dit zijn elementen waarvan we denken dat ze niet erg vaak gaan veranderen, maar het is wel mogelijk. De naam van de stad bijvoorbeeld (en die komt 2 keer voor), als we ons programma willen doorgeven aan een andere CoderDojo-organisatie. Of de locatie – die is al een keer veranderd (we zaten vroeger in drukkerij Roose). En het aantal verschillende leeftijden dat aanwezig gaat zijn (alle leeftijden van 7 tot en met 16 jaar). En ook het beginuur gaat niet snel wijzigen, maar het kan wel. Het aantal verschillende leeftijden is in het blauw aangeduid, omdat dit een berekende waarde is: als de leeftijdsgrenzen wijzigen, moet deze waarde ook mee wijzigen. Een aantal elementen is in het groen aangeduid. Dit zijn de elementen waarvan we denken dat ze veel sneller gaan wijzigen. Het aantal ingeschreven kinderen per sessie, en de datum van de volgende sessie. Deze waarden gaan we niet in onze programmacode opnemen, om te vermijden dat we elke maand ons programma moeten aanpassen. In de plaats daarvan gaan we die waarden vragen aan de gebruiker, voor we ons tekstje laten zien. We gaan in ons programma intensief gebruik maken van variabelen. Variabelen zijn een soort kleine doosjes waar we een waarde kunnen insteken, en die op elk moment weer kunnen uithalen. Let op, de naam die je kiest voor je variabele mag geen Python-commando zijn. Je mag je variabele dus niet bv. “print” noemen. Python [7] Variabelen en constanten versie 12/03/2015 1/4 Om een variabele te definiëren kiezen we een naam, en kennen we de waarde toe aan de variabele door er een = teken tussen te zetten. Zo dus: naam = 'Bart' Voeren we even daarna volgende regel uit: print('Hallo', naam) dan verschijnt op ons scherm: Hallo Bart De variabele “naam” is tijdens de uitvoering van het programma dus vervangen door zijn inhoud, zijnde “Bart”. De inhoud van een variabele kan overschreven worden. Bekijk volgende code: naam = 'Jan' naam = 'Lotte' print('Hoi', naam) Wat zal er verschijnen, denk je? Dit: Hoi Lotte De variabele “naam” werd eerst gevuld met de inhoud “Jan”, en werd direct daarna overschreven met “Lotte”. Enkel de laatste naam blijft bewaard in de variabele. Soms willen we niet dat de inhoud van een variabele kan overschreven worden in de programmacode. Als we bv. een variabele “PI” definiëren: PI = 3.14159265358979 dan is het niet de bedoeling dat PI in de loop van het programma wordt vervangen door een ander getal. PI is dus eigenlijk geen variabele maar een constante. Let er trouwens op dat we in Python komma-getallen met een punt schrijven. Dus: 3.14, niet 3,14. Andere programmeertalen hebben manieren om constanten te definiëren, zodat ze nooit meer kunnen overschreven worden. Python heeft dat jammer genoeg niet. Het is dus niet mogelijk om in Python een variabele te definiëren die niet meer kan overschreven worden. Opletten is dus de boodschap. Om visueel duidelijk te maken wat er een variabele is en wat er een constante is, is het een goede gewoonte om namen van constanten in HOOFDLETTERS te schrijven. Dat is geen verplichting, en dat verandert niets aan de manier van werken, maar het is een goede gewoonte waarmee we duidelijk maken dat een bepaalde variabele nooit zal / mag veranderen. Python [7] Variabelen en constanten versie 12/03/2015 2/4 Goed! Terug naar ons programma om reclame te maken voor CoderDojo. We bepalen nu welke variabelen we gaan gebruiken, en of ze constant gaan zijn (en we ze dus in hoofdletters schrijven), of ze variabel gaan zijn, of als het berekende waarden zijn. volgendeDatum STAD_NAAM aantalLeeftijden aantalKinderen LOCATIE MIN_LEEFTIJD MAX_LEEFTIJD STARTUUR We beginnen ons programma met het definiëren van onze constanten STAD_NAAM = 'Dendermonde' LOCATIE = 'de jeugddienst aan de achterkant van de bib' MIN_LEEFTIJD = 7 MAX_LEEFTIJD = 16 STARTUUR = 10 Nu we de minimum leeftijd en de maximum leeftijd kennen, kunnen we het aantal leeftijden berekenen. Dat is de maximum leeftijd min de minimum leeftijd, en dan doen we daar eentje bij. aantalLeeftijden = MAX_LEEFTIJD - MIN_LEEFTIJD + 1 Tenslotte moeten we nog een aantal dingen vragen aan onze gebruiker van ons programma. Dat doen we met het input-commando: volgendeDatum = input('Geef de volgende datum in: ') aantalKinderen = input('Hoeveel kinderen zijn er ingeschreven voor de volgende sessie? ') Het programma zal nu even stoppen om te vragen wat de volgende datum is en hoeveel kinderen er ingeschreven zijn. Belangrijke opmerking: Je mag de schrijfwijze van je variabele-namen volledig zelf kiezen, maar eens je iets gekozen hebt, moet je je er wel aan houden. Hoofdletters doen er toe in Python! Als we dus aantalKinderen bepaald hebben als variabele, dan is dat iets anders dan AantalKinderen, of aantalkinderen, of AANTALKINDEREN. Nu we alle variabelen hebben, is het tijd om de tekst weer te geven. Dat kunnen we bv. doen door in een print-commando de tekst op te knippen in verschillende stukken, en met komma’s de tekst-fragmenten en de variabelen aan elkaar te plakken. print('We verwachten je bij CoderDojo', STAD_NAAM, '! ') print('De volgende sessie gaat door op zaterdag', volgendeDatum, 'in', LOCATIE, '(', STAD_NAAM, ').') print('We verwachten', aantalKinderen, 'kids van', MIN_LEEFTIJD, 'tot', MAX_LEEFTIJD, 'jaar (dat zijn', aantalLeeftijden, 'verschillende leeftijden!)') print('Afspraak om', STARTUUR, 'uur!') Python [7] Variabelen en constanten versie 12/03/2015 3/4 Ons programma is klaar om uit te voeren. En? Werkt alles? En probeer nu eens de variabelen te veranderen, en voer het programma dan opnieuw uit. Als je het lastig vindt om je tekst op te delen in stukken, bestaat er nog een andere manier om variabelen op te nemen in een tekst. Het bovenstaande stuk code kunnen we ook zo schrijven: print('''We verwachten je bij CoderDojo %s! De volgende sessie gaat door op %s in %s (%s). We verwachten %s kids van %s tot %s jaar (dat zijn %s verschillende leeftijden!) Afspraak om %s uur!''' % (STAD_NAAM, volgendeDatum, LOCATIE, STAD_NAAM, aantalKinderen, MIN_LEEFTIJD, MAX_LEEFTIJD, aantalLeeftijden, STARTUUR)) Hierbij hebben we 2 nieuwe dingen gedaan: We hebben slechts één print-commando gebruikt, in plaats van een commando voor elke regel. Om een lang stuk tekst te maken van meerdere regels laat je de tekst beginnen en eindigen met 3 enkele quotes ('''). Het tweede wat we gedaan hebben, is plaatshouders voorzien voor waar de variabelen moeten komen. Dit doen we door de %s notatie. Overal waar een %s staat, moet er een variabele komen. De variabelen worden achteraf toegevoegd door na de string een %-teken te zetten en vervolgens alle variabelen op te lijsten tussen haakjes. Om dat laatste beter te snappen krijg je hier nog een eenvoudiger voorbeeld: print('Mijn naam is %s en ik ben %s jaar. ' % (naam, leeftijd)) Als je deze code uitvoert krijg je bv.: Mijn naam is Bert en ik ben 11 jaar. Lege variabelen: None Soms willen we een variabele initialiseren. Dat wil zeggen dat we er in ons programma voor zorgen dat een variabele bestaat, zodat we later in het programma de variabele bijvoorbeeld in een vergelijking kunnen gebruiken. Als we een variabele maken in Python, moeten we aan Python vertellen wat de inhoud van die variabele is. Maar soms willen we dat onze variabele voorlopig nog een leeg doosje is. We bepalen dus nog geen waarde. Soms is het niet moeilijk om te bedenken welke waarde we er dan moeten aan geven. Als we bv. weten dat onze variabele een tekst wordt, kunnen we een lege tekst in de variabele steken. Dat doen we door de variabele gelijk te stellen aan '' (= 2 quote-tekentjes). Of een leeg getal kunnen we gelijk stellen aan 0. Maar wat nu als we echt nog totaal geen idee hebben van de soort waarde die in onze variabele gaat terecht komen? Dan kunnen we het speciale Python-keyword None gebruiken. Dan maakt Python echt een volledig lege variabele aan, waar nog niets van inhoud in zit. Python [7] Variabelen en constanten versie 12/03/2015 4/4 Enkele voorbeelden: leegGetal = 0 legeTekst = '' legeVariabele = None Er zit nog veel meer in variabelen Wat je op deze leerfiche geleerd hebt is nog maar het topje van de ijsberg als het op variabelen aankomt. Variabelen worden pas echt interessant als ze dynamisch berekend worden (bv. het aantal dagen tussen vandaag en de volgende CoderDojo-sessie) en als we er complexe bewerkingen mee doen. Of als we beslissingen laten afhangen van de inhoud van variabelen (“Als de leeftijd kleiner is dan 11, doe dan …”). Wat nog ontbreekt in ons programma is invoervalidatie (input validation). Daarbij controleren we in ons programma of de gebruiker wel de juiste soort gegevens invoert. Als we de datum vragen kan je nu perfect “varkentjesdag” invullen en als het aantal kinderen gevraagd wordt kan je “veel te veel” invullen. Je programma zal werken en een grappige tekst tonen, maar een goede programmeur houdt dat soort verkeerde invoer tegen. Maar eerst moet je iets over types leren. En daar gaat de volgende leerfiche over. Invoervalidatie komt aan bod in leerfiche [17] Fouten vinden en oplossen. Oefening Maak je eigen programma waarbij je de computer een aantal variabelen laat vragen, zoals naam, leeftijd, favoriete kleur, favoriete boek, favoriete film, favoriete game, huisdier,… en brouw er dan een tekstje mee, bijvoorbeeld: Dag Arne, wat leuk dat je er bent! Ben jij al 11 jaar? Tof! Je favoriete film is Despicable Me! Waaw, die vind ik ook tof. En ik speel ook heel graag Minecraft. Daaag! Python [7] Variabelen en constanten versie 12/03/2015 5/5 [8] De ene 1 is de andere niet Volg mee via 08_Types.py In de volgende leerfiche gaan we rekenen met Python. Dat kan je in een programma doen, maar dat kan je ook gewoon vanuit het Shell-venster doen. We geven al een voorsmaakje: hoeveel is 1 + 2? Typ de som in het Shell-venster in, en druk op enter >>> 1 + 2 3 >>> Fantastisch! De uitkomst is 3. Dus onze meester van wiskunde heeft niet gelogen… Je kan ook rekenen met variabelen. Typ volgende 2 regels na elkaar in de Shell in: a = 1 b = 2 En typ nu a + b En opnieuw verschijnt dezelfde uitkomst: 3. Typ nu eventjes letterlijk volgende regels in: c = '1' d = '2' en nu: c + d Woeps!! Wat krijgen we nu? 1 + 2 blijkt 12 te zijn? Dus de meester van wiskunde heeft toch gelogen?? Neen, niet echt. Wat er bij de c + d bewerking gebeurt is, is dat er niet twee getallen opgeteld zijn bij elkaar, maar wel 2 stukken tekst aan elkaar geplakt zijn. Eigenlijk staat er dit: '1' + '2' Python onderscheidt verschillende types van variabelen, en leidt het type af uit de inhoud. Python [8] De ene 1 is de andere niet versie 12/03/2015 1/4 Types: int, float, string en bool Bekijk de volgende code: getal1 = 1 getal2 = 1.0 getal3 = '1' waarOfVals = True # # # # Type: Type: Type: Type: int float str (string) bool In dit stukje code zie je 4 belangrijke types van variabelen in Python: getal1 is een integer (int), of een geheel getal. Dit is een positief of een negatief getal (bv. -3) zonder cijfers na de komma. getal2 is een floating-point-getal (float), of een getal met cijfers na de komma. Ook al staat er in dit geval alleen een 0 na de komma, zal Python dit toch intern als een float opslaan, omdat we de 1.0 notatie gebruikt hebben. Je kan dat trouwens nakijken via volgende code: type(getal2) Merk trouwens op dat we in Python een punt (.) gebruiken als ‘komma’ en dus geen komma (,) getal1 en getal2 zijn allebei getallen. Ondanks het feit dat ze van een verschillend type zijn (int en float) mag je er toch mee rekenen. Dus getal1 + getal2 levert de verwachte uitkomst van 2 op. (eigenlijk 2.0 om precies te zijn) getal3 is géén getal maar een string. Dat komt omdat we hier de 1 tussen aanhalingstekens gezet hebben. Om met getal3 te kunnen rekenen moet het stukje tekst dus eerst omgezet worden naar een getal. Dat kan via de functie int() getal1 + getal3 getal3 + getal3 getal1 + int(getal3) # Dit levert een fout op, we tellen string op bij getal # Dit levert '11' op als resultaat # Dit levert 2 op als resultaat Om een string naar een getal te kunnen omzetten moet de inhoud wel duidelijk een getal zijn. Wat gebeurt er als we int('een') proberen te doen of int('minecraft')? In het rijtje variabelen dat we gedefinieerd hebben, hadden we nog één variabele over: waarOfVals. Die hebben we gelijk gemaakt aan True. True en False zijn 2 speciale waarden. Ze betekenen “waar” en “onwaar” en in programmeertalen noemen we dit Booleaanse waarden. We gaan zometeen wat dieper in op die Booleaanse waarden. Voorlopig hoef je enkel te onthouden dat we er niet mee kunnen rekenen in Python. Om 2 variabelen bij elkaar op te tellen of ze te vergelijken, moeten het variabelen van dezelfde soort zijn. Je kan dus een getal niet met een stuk tekst (string) vergelijken. Je kan wel 2 stukken tekst met elkaar vergelijken of aan elkaar plakken, of 2 getallen vergelijken of optellen. Als we aan een gebruiker vragen om iets in te typen via het input-commando, dan levert dit altijd een string op. Dat zagen we onder andere in het spokenspel: daar moesten we het deurnummer dat gekozen werd eerst omzetten naar een int voor we het konden vergelijken met het willekeurig getal dat de computer gekozen had. Python [8] De ene 1 is de andere niet versie 12/03/2015 2/4 Dat moet je ook onthouden als we getallen aan het vergelijken zijn. 1 is gelijk aan 1, dat is duidelijk. Maar 1 (zonder aanhalingstekens) is niet gelijk aan '1' (met aanhalingstekens). 1 == 1 1 == '1' 1 == int('1') # waar # niet waar # waar Booleaanse waarden: True en False In de voorbeeldjes hierboven zie je al het gebruik van de woorden ‘waar’ en ‘niet waar’ (of ‘onwaar’). In het Engels is dat True en False. Elke vergelijking in Python wordt geëvalueerd naar ‘waar’ of ‘onwaar’. Als ik je vraag of 3 kleiner is dan 5, dan zeg je me dat dat waar is. Als ik vraag of 4 groter is dan 8, dan is dat onwaar. Bekijk het volgende stukje code even. if betekent ‘als’ en else betekent ‘anders’. leeftijd = input('Hoe oud ben je? ') if int(leeftijd) < 7: print('Je bent nog te jong voor CoderDojo') else: print('Python leren is vast iets voor jou!') Het programma gaat eerst de leeftijd vragen, en gaat dan kijken of die leeftijd jonger is dan 7 of niet. Als we bv. ‘6’ invullen als leeftijd dan zal de regel if int(leeftijd) < 7: gelijk gemaakt worden (dat noemen we “evalueren”) met ‘True’ en dan wordt het zinnetje 'Je bent nog te jong voor CoderDojo' op het scherm getoond. Als we ‘8’ invullen zal de if evalueren naar ‘False’ en dan wordt het tweede zinnetje getoond. We mogen ook letterlijk True en False schrijven. We zouden bv. kunnen schrijven: if True: print('Dit is altijd waar.') else: print('Dit zinnetje wordt nooit getoond.') maar dat heeft weinig zin, want het else-stuk wordt daarbij nooit uitgevoerd. We kunnen True ook gebruiken om een oneindige lus te maken – dat is een stukje programma dat altijd herhaald wordt en nooit stopt. while True: print('Oneindig veel zinnetjes!') Als je het bovenstaande programma uitvoert zal je Ctrl+C moeten drukken om het te stoppen, want anders blijft het lopen tot je een lange, grijze baard hebt! Python [8] De ene 1 is de andere niet versie 12/03/2015 3/4 Nog een allerlaatste puntje over Booleaanse waarden: Python is niet altijd even strikt op zijn types, en je hebt dus niet altijd een strikte Booleaanse waarde nodig om een beslissing te nemen. Volgend stukje code zal werken in Python: a = 1 if a: print("Hoera! Ik kan de integer 'a' gebruiken in een if-functie!") Wat echter veel “netter” is, is om expliciet a te vergelijken met bv. 0: a = 1 if a > 0: print('Joepie, dit lukt!') Strings “optellen” We springen al even vooruit naar de leerfiche over strings. Daar zal je zien dat we het + teken gebruikt om 2 strings (stukken tekst) aan elkaar te hangen. Dat hadden we bij het begin van deze leerfiche ook al gezien. Dus: a = '1' b = '2' c = a + b print(c) geeft als uitvoer niet 3 maar: 12 En leeftijd = '10' print('Ik ben ' + leeftijd + ' jaar oud') drukt de regel Ik ben 10 jaar oud af op het scherm. Let op, dit werkt alleen als we strings bij elkaar optellen. Onderstaande code geeft een fout; snap je waarom? print('Ik ben ' + 10 + ' jaar oud') Python [8] De ene 1 is de andere niet versie 12/03/2015 4/4 Strings van elkaar aftrekken kan niet zomaar. Dus print('CoderDojo' - 'Dojo') levert een fout op. Je kan wél strings “vermenigvuldigen”. Probeer maar eens: print('bla' * 10) Oefening Maak enkele variabelen aan en experimenteer met de inhoud. Zorg dat je verschillende soorten variabelen hebt, zoals integers, floating-point getallen, strings en booleaanse variabelen. Check hun type met de functie type(). En experimenteer ook met het omzetten van strings naar integers via int(), en omgekeerd via str(). Python [8] De ene 1 is de andere niet versie 12/03/2015 5/5 [9] Rekenen met Python De Python Shell is eigenlijk een uitstekende rekenmachine – dat hadden we al gezien in de vorige leerfiche. Typ op de lijn van het Shell-venster maar eens een paar sommen: >>> >>> >>> >>> >>> 98766 + 567 80 - 54 80+12+56+54+90+67-54 45 * 3 35 / 0 (vooral die laatste is een regelrecht succes!) Volg mee via 09_Rekenen.py Om te rekenen in Python gebruiken we de volgende operatoren: + optellen bv. 4 + 5 - aftrekken bv. 12 - 7 * vermenigvuldigen bv. 9 * 3 / delen bv. 12 / 3 // floor division deling waarbij het resultaat afgerond wordt naar beneden bv. 20 // 6 (= 3) % modulus de rest bij deling bv. 20 % 6 (= 2) ** exponent bv. 4 ** 2 (= 16) Het gebruik van haakjes is daarbij belangrijk om de voorrang te wijzigen. Bij 3 + 4 * 5 krijgt het maal-teken voorrang op het plusteken, en is de uitkomst 23. Bij (3 + 4) * 5 krijgt het plus-teken voorrang, en is de uitkomst 35. Python [9] Rekenen met Python versie 12/03/2015 1/1 Toekenningsoperatoren We gebruiken in Python het is-gelijk-aan-teken (=) om een bepaalde waarde toe te kennen aan een variabele. Om met andere woorden een variabele gelijk te stellen aan een bepaalde waarde. Bij som = 3 + 4 heeft de variabele ‘som’ de waarde 7 gekregen. Je kan in Python verkorte toekenningsoperatoren gebruiken om iets bij te tellen bij een variabele, of om iets af te trekken. Als we bv. 8 willen optellen bij wat er al in ‘som’ zit, dan kunnen we dat zo schrijven: som = som + 8 Het nadeel is dat we ‘som’ 2 keer moeten schrijven. Daarom biedt Python hiervoor een verkorte notatie aan: som += 8 Met deze notatie vragen we om 8 bij te tellen bij ‘som’. Dezelfde notatie bestaat voor de andere operatoren: = toekennen van een waarde bv. aantal = 5 += bijtellen bv. aantal += 4 -= aftrekken van bv. aantal -= 3 *= vermenigvuldigen met bv. aantal *= 5 /= delen door bv. aantal /= 2 In Python kennen we ook nog vergelijkingsoperatoren en logische operatoren. Die komen aan bod in leerfiche [11] Oefening Experimenteer in het Shell-venster wat verder met de verkorte operatoren Maak ook een complexe som door meerdere operatoren en haakjes te gebruiken. Python [9] Rekenen met Python versie 12/03/2015 2/2 [10] Werken met tekst (strings) Algemene principes In programmeertalen wordt een variabele waarin tekst bewaard wordt een string genoemd. “String” is Engels voor “koordje” en doet denken aan een koordje waar verschillende letters op geregen zijn. Zo moet je een string in Python ook wat zien: een verzameling van individuele karakters. In leerfiche [12] gaan we leren werken met lijsten (arrays) en we gaan zien dat een string eigenlijk een lijst met letters is. Volg mee via 10_Strings.py Een string in Python wordt altijd weergegeven tussen aanhalingstekens, enkele (') of dubbele ("). Dat hadden we al gezien in leerfiche [8] – daar zagen we dat 1 zonder aanhalingstekens iets anders is in Python dan '1'. naam = 'Tom' woonplaats = 'Oudegem' hobby = "CoderDojo" Willen we een string van meerdere regels maken, dan gebruiken we daar best de '''-notatie voor. Je begint je string met drie enkele aanhalingstekens, en je eindigt hem er ook weer mee. Alle tussenliggende regels worden in de string opgenomen. gedicht = '''Er stond een boom in Zweden Met takken en een bast Dat is nu lang geleden Die boom is nu mijn kast''' print(gedicht) Speciale karakters met \backslash Soms willen we in een string een speciaal karakter opnemen, zoals een witregel of aanhalingstekens. Daar bestaan speciale karakters voor. Als we een aanhalingsteken willen gebruiken in een string, moeten we altijd opletten. Want de string zelf is immers ook omsloten door aanhalingstekens. Python [10] Werken met tekst (strings) versie 12/03/2015 1/6 Bekijk volgende code: print('Het is vandaag zo'n mooie dag!') Deze code loopt fout. En zie je ook waarom? De apostrof in zo’n zorgt ervoor dat de string wordt afgesloten, en Python weet niet wat het nog met n mooie dag! moet aanvangen. Dat kan je oplossen door in dat geval dubbele aanhalingstekens te gebruiken: print("Het is vandaag zo'n mooie dag!") Net zoals je zal moeten enkele aanhalingstekens gebruiken om deze string weer te geven: print('Hij zei: "Het is vandaag prachtig weer!" en hij liep fluitend verder.') Maar vroeg of laat komen we in de problemen, omdat we een string hebben met én enkele aanhalingstekens, én dubbele. Bv. het zinnetje Hij zei: "Het is vandaag zo'n mooie dag!" en hij liep fluitend verder. kan problematisch worden. Dat lossen we op door de apostrof in de string te escapen of over te slaan. En dat doen we met een backslash: \ print('Hij zei: "Het is vandaag zo\'n mooie dag!" en hij liep fluitend verder.') En zo kent Python nog wel een aantal karakters, die een speciale behandeling krijgen binnen strings. Als je bv. \n invoegt in je string, wordt er een witregel ingevoegd. Onderstaande tabel geeft een overzichtje. Python [10] Werken met tekst (strings) \n spring naar volgende regel \t tab \' enkele quote \" dubbele quote \\ de backslash (\) zelf versie 12/03/2015 2/6 Strings bewerken We leerden eerder ook al hoe we strings aan elkaar kunnen hangen. Strings aan elkaar hangen wordt met een groot woord concateneren genoemd. Om strings te concateneren in Python gebruiken we de + operator. woorddeel1 = 'Coder' woorddeel2 = 'Dojo' stad = 'Dendermonde' supergaaf = woorddeel1 + woorddeel2 + ' ' + stad Ook de * operator kunnen we gebruiken op strings, om strings te herhalen. print('CoderDojo is ' + 'super'*10 + 'cool') Soms willen we aan Python wat informatie vragen over een string. Als we bijvoorbeeld willen weten hoe lang een string is, gebruiken we len(). woord = 'Superkwalikwantiviaextraquasiotisch' print(len(woord)) De functie len() levert als resultaat een getal (int) op. Dat wil zeggen dat je er ook mee mag rekenen. woordje = 'kort' tienwoordjes = 10 * len(woordje) # Resultaat: 40 Python kan ons ook helpen om één letter of bepaalde delen van een woord te geven. Maar daarvoor moet je eerst iets snappen over hoe lijsten genummerd worden in programmeertalen. In tegenstelling tot mensen – die bij 1 beginnen tellen – begint een computer bij 0 te tellen. Vreemd, nietwaar? Kijk bijvoorbeeld hoe de letters in het woord ‘Vreemd’ geteld worden: V R E E M D 0 1 2 3 4 5 De letter ‘V’ staat op positie 0, de letter ‘R’ staat op positie 1, enzovoort. Dus ondanks dat dit een woord van 6 letters is, staat de laatste letter op positie 5. Daar moeten we rekening mee houden. Als we nu in een programma een letter willen opvragen van een woord, doen we dat met vierkante haken. Als volgt: raar = 'Vreemd' print(raar[5]) # de 'd' Die notatie met vierkante haken zal je in leerfiche [12] ook zien terugkomen als we het over lijsten hebben. Python [10] Werken met tekst (strings) versie 12/03/2015 3/6 De notatie met de vierkante haken kan ook gebruikt worden om een deel van een string te laten zien. Als we bv. de eerste 3 letters willen laten zien kunnen we raar[:3] gebruiken. Willen we alles vanaf de vierde letter tot aan het einde laten zien, dan gebruiken we raar[3:], en willen we de tweede tot vijfde letter laten zien, gebruiken we raar[1:5]. Het eerste cijfer wordt meegenomen (we beginnen dus vanaf positie 1), het laatste cijfer niét (we gaan dus door tot net vóór positie 5). print(raar[:3]) # Vre print(raar[3:]) # emd print(raar[1:5]) # reem Variabelen opnemen in strings In leerfiche [7] hebben we intensief gewerkt met variabelen en constanten, en hebben we ook gezien hoe we deze kunnen opnemen in strings. Dat kan op een aantal manieren. naam = 'Jarno' stad = 'Dendermonde' print('Ik ben', naam, 'uit', stad) print('Ik ben ' + naam + ' uit ' + stad) print('Ik ben %s uit %s' % (naam, stad)) In de bovenstaande voorbeeldjes zie je dat de variabelen naam en stad op 3 manieren worden opgenomen in strings: door de verschillende stukken van de gewenste tekst in het print-commando na elkaar te zetten door ze met komma’s te scheiden door een grote nieuwe string te maken door alle kleine strings met + bij elkaar “op te tellen” (te concateneren) door de %s notatie te gebruiken in een print-commando Voor het bovenstaande voorbeeld zijn dat drie goede opties. Maar let op met het samenvoegen van strings met het + teken. Want om strings aan elkaar te hangen, moeten alle verschillende delen van de “optelling” ook strings zijn! Bekijk het onderstaande voorbeeld: leeftijd = 10 print('Ik ben', naam, 'en ik ben', leeftijd, 'jaar') print('Ik ben ' + naam + ' en ik ben ' + leeftijd + ' jaar') Dit loopt fout. Bij de uitvoering van het programma wordt de eerste print correct uitgevoerd, maar de tweede zorgt voor een fout: TypeError: Can't convert 'int' object to str implicitly Wat is er gebeurd? leeftijd is geen string maar een getal (integer) en kan dus niét bij de string samengevoegd worden. Python [10] Werken met tekst (strings) versie 12/03/2015 4/6 Dat lossen we op door de werkwijze met het +teken te mijden, of door de integer expliciet om te zetten naar een string. Dat kan met de str() functie. print('Ik ben ' + naam + ' en ik ben ' + str(leeftijd) + ' jaar') Intermezzo: Invoer, verwerking en uitvoer Nu we zo veel over strings af weten en zometeen nog het print-commando en het input-commando in detail bekijken, is het tijd om het even te hebben over een basismodel uit de informatica: Invoer Verwerking Uitvoer Een computer is eigenlijk Engels voor “berekenaar”. Een computer is eigenlijk een domme machine die aan de slag gaat met wat we invoeren, die vervolgens die informatie verwerkt, en tenslotte de verwerkte informatie aan de gebruiker teruggeeft (= uitvoer). Dit model wordt in het Engels Input-Processing-Output genoemd. We voeren informatie in de computer in via het toetsenbord, de muis, de scanner of een touchscreen. En de computer voert de verwerkte informatie weer uit via het beeldscherm, de printer of de luidsprekers. Zo zullen onze computerprogramma’s ook werken. We vragen iets aan de gebruiker van ons programma via het input-commando of we maken gebruik van de huidige tijd en datum, of andere omgevingsvariabelen. Vervolgens gaat ons programma met een hoop if-then-else lusjes (zie de volgende leerfiche hiervoor) beslissingen nemen en de informatie verwerken. En de verwerkte informatie gaan we wegschrijven naar een bestand of via het print-commando weergeven op het scherm. Of nog ietsje concreter, in Minecraft: invoer: je drukt op het pijltje naar boven verwerking: het Minecraft-programma vangt die toets op, en berekent welke dingen er moeten veranderen op het scherm om je mannetje te laten bewegen uitvoer: je mannetje gaat een stap vooruit op het scherm Python [10] Werken met tekst (strings) versie 12/03/2015 5/6 Invoer: Strings vragen aan de gebruiker Het input-commando hebben we ondertussen al vrij vaak gebruikt in voorbeeldjes. En het is een heel eenvoudig commando. Dus we gaan deze paragraaf simpel en kort houden, en dit zou allemaal pure herhaling moeten zijn. :-) lievelingsdier = input('Wat is je favoriete dier? ') Bij de functie input() kan je tussen de haakjes een string zetten die zal verschijnen op het scherm. Het programma pauzeert even en de gebruiker krijgt de kans om iets in te typen. Wat de gebruiker intypt zal altijd een string zijn, en moet dus indien nodig nog omgezet worden naar een getal (via de int()- of float()-functie). Als de gebruiker in het bovenstaande voorbeeld “kat” intypt, zal de string “kat” opgeslagen worden in de variabele ‘lievelingsdier’. Uitvoer: print kan meer dan je denkt We hebben in onze programma’s al heel veel print gebruikt als commando om een regel op het scherm te schrijven. Maar wist je dat je aan print ook een aantal parameters kan geven, om zich wat anders te gedragen? Bekijk even de volgende code: print('Lijst met films: ') print('Frozen', 'Cars', 'Finding Nemo', 'Big Hero 6') Standaard zal Python ervoor zorgen dat elk print-commando op een nieuwe regel verschijnt. print zorgt er ook voor dat de variabelen die met komma’s gescheiden zijn van elkaar in het print-commando uiteindelijk op de uitvoerregel zullen verschijnen met spaties ertussen. Dit is dus de uitvoer: Lijst met films: Frozen Cars Finding Nemo Big Hero 6 Bij een print-commando kan je parameters opgeven, dat zijn een aantal extra instructies om de print zich een beetje anders te laten gedragen. De parameters die je mag opgeven zijn: sep: om op te geven waarmee de strings binnen een print-commando worden gescheiden van elkaar (standaard is dit een spatie) end: om op te geven wat er op het einde van een print-commando komt (standaard is dit een nieuwe regel, een \n dus) Kijk goed naar onderstaande code: print('Lijst met films: ', end='') Python [10] Werken met tekst (strings) versie 12/03/2015 6/6 print('Frozen', 'Cars', 'Finding Nemo', 'Big Hero 6', sep=' / ', end=' ###\n') De print-commando’s zijn hier een beetje aangepast. Bij de eerste print is er opgegeven dat er op het einde géén nieuwe regel moet komen ('' is een lege string), bij de tweede is er opgegeven dat er een slash als scheidingsteken moet gebruikt worden, en dat er op het einde drie spoorwegtekentjes moeten gezet worden voor er naar een nieuwe regel gesprongen wordt. Dit is de uitvoer: Lijst met films: Frozen / Cars / Finding Nemo / Big Hero 6 ### Oefeningen Maak een programma waarin je een aantal strings definieert (dit wil zeggen dat je variabelen maakt waar je als inhoud een tekst in steekt). Gebruik zowel enkele aanhalingstekens als dubbele aanhalingstekens. Maak een aantal strings waarbij je aanhalingstekens binnenin de string gebruikt. Hoe moet je dat alweer doen? Gebruik het print-commando om de strings naar het scherm te schrijven. Geef enkele parameters mee aan je print-commando om een scheidingsteken en een eind-teken op te geven. Maak één print-commando waarmee je je favoriete films op het scherm laat verschijnen. Let op! Zorg dat elke film op een nieuwe regel verschijnt. Gebruik het print-commando ook om een tekst weer te geven waarin je een aantal variabelen laat verschijnen, zoals de naam en de leeftijd. Op welke manier pak je dit aan? Gebruik de notatie met de vierkante haken om het derde teken van een string te tonen. Gebruik dezelfde notatie ook om delen van strings te laten zien, bv. vanaf de vierde letter tot het eind, of vanaf de derde letter tot en met de zesde letter. Een doordenkertje: schrijf van een bepaalde string de voorlaatste letter naar het scherm. Python [10] Werken met tekst (strings) versie 12/03/2015 7/7 [11] Beslissingen nemen Als een programma gewoon een lange rij instructies zou zijn, zou programmeren heel saai zijn. In werkelijkheid gaan we in onze programma’s rekening houden met een heleboel zaken die heel veranderlijk kunnen zijn. We onderzoeken wat de situatie is, en we nemen aan de hand van wat we ontdekt hebben beslissingen. We grijpen even terug naar RoboMind om dat te illustreren. Je krijgt als opdracht om in RoboMind een robot van links naar rechts over het scherm te laten rijden. Als de RoboMind-wereld er zo uit ziet, is het programma niet moeilijk: Ons programma kan er dan als volgt uit zien: rechts vooruit(13) Het probleem is: we kunnen toch niet voor elke mogelijke wereld een apart programma schrijven? Want wat als er nu een blok in de weg staat? Python [11] Beslissingen nemen versie 12/03/2015 1/6 Ons programma van daarnet mislukt: de robot rijdt tegen het blok, en blijft er tegen duwen tot zijn batterij leeg is. We zouden dat kunnen oplossen door te programmeren dat de robot eerst zes stappen naar voren moet doen, dan rond het blok moet rijden, en dan nog vijf stappen naar voren moet doen. Maar dat is een slechte oplossing, want als het blok ergens anders staat, moet ik wéér een nieuw programma schrijven. Veel beter is het om bij elke stap te kijken of er geen obstakel is. Als er geen obstakel is rijd je door, als er wel een is rijd je er rond. Ons programma ziet er dan zo uit: rechts herhaal { vooruit(1) als(voorIsObstakel) { links vooruit(1) rechts vooruit(2) rechts vooruit(1) links } } Dit programma werkt nu in een heleboel situaties, en raakt op intelligente wijze aan de overkant. (Opmerking: de gekozen oplossing is hier nog niet de beste – er kan nog heel wat aan het programma verbeterd worden. Maar dat maakt ons programma een stuk langer, en dan begin je je af te vragen of dit een Python-cursus is of een RoboMind-cursus. En dat is natuurlijk niet de bedoeling.) Terug naar Python! Ook in Python willen we beslissingen nemen gebaseerd op bv. wat de gebruiker intypt, hoe laat het is of wat het resultaat van een som is. Dat doen we niet met als…anders zoals in RoboMind, maar met if…else. En met operatoren. Volg mee via 11_Beslissingen.py Python [11] Beslissingen nemen versie 12/03/2015 2/6 Vergelijkingsoperatoren Om een beslissing te nemen gaan we heel vaak 2 variabelen vergelijken. We kijken of 2 variabelen gelijk zijn aan elkaar, of ze groter of kleiner zijn dan elkaar, of de lengte van een string kleiner of groter is dan een bepaald getal, … Daarvoor gebruiken we in Python de volgende vergelijkingsoperatoren: == controleer of twee variabelen gelijk zijn aan elkaar bv. a == 2 != is niet gelijk aan bv. a != b > is groter dan bv. b > 8 < is kleiner dan bv. a < 5 >= is groter dan of gelijk aan bv. a >= 9 <= is kleiner dan of gelijk aan bv. b <= 3 Let op! Je mag de vergelijkingsoperator == niet verwarren met de toekenningsoperator =. Er is dus een héél groot verschil tussen a = 5 a == 5 # Hiermee maken we a gelijk aan 5 # Hiermee controleren we of a gelijk is aan 5 # Deze vergelijking wordt dan True Het resultaat van een vergelijking is altijd True of False. Dat resultaat kunnen we ook opslaan in een variabele. We kunnen bv. zeggen: leeftijd = 8 minimumleeftijd = 7 kindIsOudGenoeg = leeftijd >= minimumleeftijd De variabele kindIsOudGenoeg is dus een Booleaanse variabele waar de waarde True of False zal in zitten (in dit geval True). Een beetje verder in de code kunnen we dan schrijven: if kindIsOudGenoeg: print('Welkom bij CoderDojo!') Python [11] Beslissingen nemen versie 12/03/2015 3/6 if … else / if … elif … else Een “als-dan”-beslissing nemen we zo in Python: if dagVanDeWeek == 'zaterdag': print('Het is CoderDojo-dag!') Hierbij kijken we naar de waarde van de variabele dagVanDeWeek, en we vergelijken deze met ‘zaterdag’. Als het gelijk is aan elkaar, printen we een zinnetje. Anders doen we niets. We zeggen dus alleen wat er moet gebeuren als iets waar is, en we zeggen niet wat er moet gebeuren als het onwaar is. Willen we dat wél expliciet doen, dan voegen we een else-stuk toe (= anders). if dagVanDeWeek == 'zaterdag': print('Het is CoderDojo-dag!') else: print('Nog even wachten op CoderDojo...') Nu zal er àltijd iets verschijnen. Ofwel het zinnetje over CoderDojo-dag, ofwel het wacht-zinnetje. Wat als we twee mogelijkheden willen bekijken voor we naar het else-stuk gaan? We willen eerst weten of het zaterdag is vandaag, dan willen we weten of het zondag is, en dan pas gaan we een ander zinnetje schrijven? Dan voegen we tussen de if en de else een elif-stukje toe. elif is een verkorte vorm voor else-if (= anders als) if dagVanDeWeek == 'zaterdag': print('Het is CoderDojo-dag!') elif dagVanDeWeek == 'zondag': print('Het weekend is bijna gedaan...') else: # Het is geen zaterdag en geen zondag print('Tijd om naar school te gaan!') Je mag zoveel elif-stukjes toevoegen als je wil. Zo kan je dus een hele reeks mogelijkheden aflopen. Logische operatoren Dankzij de elif kunnen we al meerdere mogelijkheden overlopen in een beslissingslus. Maar soms gaan we verschillende voorwaarden tegelijkertijd willen bekijken. We willen bijvoorbeeld weten of het zaterdag is én of het de tweede week van de maand is. Want op andere zaterdagen is er geen CoderDojo. Python [11] Beslissingen nemen versie 12/03/2015 4/6 Dat schrijven we zo in Python: if dagVanDeWeek == 'zaterdag' and weekVanDeMaand == 2: print('Het is CoderDojo-dag!') else: print('Geen CoderDojo vandaag...') We koppelen 2 voorwaarden aan elkaar met het and-woordje. De twee voorwaarden moeten allebei waar zijn voor we verder gaan in het if-stuk. Dit zijn de logische operatoren in Python: and en koppelt twee voorwaarden die allebei waar moeten zijn or of koppelt twee voorwaarden waarvan minstens één waar moet zijn not niet draait een voorwaarde om – waar wordt onwaar en onwaar wordt waar and en or koppelen telkens 2 Booleaanse waarden, bij not wordt er maar 1 waarde gekoppeld. not draait een voorwaarde gewoon om. In plaats van a <= 6 kan je dus ook zeggen not (a > 6) Nog even in tabelvorm hoe de logische operatoren precies werken. Links zie je 2 booleaanse waarden die gekoppeld worden aan elkaar, rechts zie je de uitkomst. Python [11] Beslissingen nemen True and True True True and False False False and False False True or True True True or False True False or False False not True False not False True versie 12/03/2015 5/6 Nog een voorbeeldje om één en ander nog eens te verduidelijken: if dagVanDeWeek == 'zaterdag' or dagVanDeWeek == 'zondag': print('Het is weekend!') In de bovenstaande code kijken we of het zaterdag is of zondag. Slechts één van beiden hoeft waar te zijn om weekend te zijn. Bij logische operatoren kan je ook met haakjes werken om voorrang te bepalen. Dat kan soms complexe structuren opleveren: if (not (dagVanDeWeek == 'zaterdag' or dagVanDeWeek == 'zondag')) and (not hetIsVakantie): print('Tijd om naar school te gaan') We ontleden even de bovenstaande voorwaarde. Stel, het is vandaag maandag, en het is geen vakantie. Dan kunnen we zeggen: dagVanDeWeek = 'maandag' hetIsVakantie = False Bekijk nu even de volledige voorwaarde: (not (dagVanDeWeek == 'zaterdag' or dagVanDeWeek == 'zondag')) and (not hetIsVakantie) We beginnen eerst met de drie gekleurde stukjes te bekijken: dagVanDeWeek == 'zaterdag' False dagVanDeWeek == 'zondag' False hetIsVakantie False We vervangen de gekleurde stukjes in de voorwaarde, en die wordt al iets eenvoudiger: (not (False or False)) and (not False) Opnieuw kunnen we vereenvoudigen: False or False False (want het is vandaag geen zaterdag of zondag) not False True (want het is vandaag geen vakantie) Nu blijft er niet veel meer over: (not (False)) and (True) Nog één vereenvoudiging – not (False) vervangen we door True. True and True True Het uiteindelijke resultaat van de hele voorwaarde is dus True. Veel moeilijke woorden om te zeggen: als het géén zaterdag of zondag is én géén vakantie (= waar) dan is het school vandaag. Python [11] Beslissingen nemen versie 12/03/2015 6/6 Oefeningen Maak een programma waarbij je aan de gebruiker een getal vraagt en achteraf zegt of het getal groter is dan 10 of niet. Breid je programma uit: geef nu drie mogelijke boodschappen: één boodschap als het getal kleiner is dan 10, één boodschap als het tussen 10 en 20 ligt en één boodschap als het groter is dan 20. Schrijf een programma met 2 booleaanse variabelen: regen en zon. Geef elk van hen een waarde (True of False). Schrijf nu een beslissingslus waarbij je eerst kijkt of het vandaag regent én of de zon schijnt. Als dat het geval is, heb je een regenboog, en dat roep je ook uit! Je beslissingsboom kan er min of meer zo uit zien: o o o als de zon schijnt en het regent Hoera! Een regenboog anders: als de zon schijnt (roep iets uit. Kan je weten of het regent, zonder dat je dat nog expliciet checkt?) anders: (roep iets uit. Je weet nu of de zon schijnt of niet. Over de regen kan je hier niets zinnigs zeggen. Snap je waarom?) Python [11] Beslissingen nemen versie 12/03/2015 7/7 [12] Tupels, lijsten en woordenboeken We kennen ondertussen al behoorlijk wat data-types in Python. Data-types zijn de verschillende vormen die een variabele kan aannemen: int (integer): gehele getallen float: kommagetallen string: stukken tekst bool: True en False, de booleaanse waarden We kennen ook al een belangrijke structuur om beslissingen te nemen in Python: de if … else structuur. In de volgende leerfiche leren we over een aantal belangrijke herhalingslussen in Python, maar eerst moeten we nog drie nieuwe data-types aan ons lijstje toevoegen: tupels lijsten woordenboeken Deze drie data-types zijn drie manieren om lijstjes te maken waarin we verschillende variabelen groeperen. De verschillen tussen de drie zijn klein, en in sommige programmeertalen (zoals PHP) wordt er zelfs geen verschil gemaakt tussen de drie soorten – het zijn allemaal vormen van arrays. Volg mee via 12_TupelsLijstenWoordenboeken.py Tupels Stel dat we in een programma willen een lijstje bijhouden van de kleuren van de regenboog. Dat kunnen we zo doen: kleur1 kleur2 kleur3 kleur4 kleur5 kleur6 kleur7 = = = = = = = 'rood' 'oranje' 'geel' 'groen' 'blauw' 'indigo' 'violet' Dat werkt perfect, maar het is natuurlijk wat jammer dat we elke variabele een andere naam moeten geven, en dat we vrij veel code moeten schrijven om die kleuren in variabelen op te slaan. Dan is dit een stuk compacter: regenboog = ('rood', 'oranje', 'geel', 'groen', 'blauw', 'indigo', 'violet') En daarmee hebben we onze eerste tupel (in het Engels tuple) gemaakt! Om een tupel te maken scheid je een aantal waarden met komma’s, en plaats je ze samen tussen gewone (ronde) haken. Python [12] Tupels, lijsten en woordenboeken versie 12/03/2015 1/8 Je kan het type controleren met het type-commando, bv. vanuit het Shell-venster: >>> type(regenboog) <class 'tuple'> Een tupel is een lijstje van verschillende variabelen die bij elkaar horen. En het verschil met lijsten (die komen zometeen aan bod) is dat de inhoud van de tupel niet meer kan gewijzigd worden. De kleuren van de regenboog gaan niet zomaar veranderen van volgorde of zo. En dat is goed, want we kunnen aan deze tupel geen kleur meer toevoegen, we kunnen geen kleur schrappen, en we kunnen geen kleur veranderen. De tupel blijft zoals ze is. Wat we wél kunnen, is de verschillende deeltjes van de tupel gebruiken in ons programma. Let op! Hier krijgen we weer te maken met die gekke telling uit de informatica: we beginnen te tellen bij 0. Dus: de eerste kleur (rood) heeft als volgnummer 0. De tweede kleur (oranje) heeft volgnummer 1. En zo gaan we verder tot we bij de zevende kleur komen (violet) – die heeft volgnummer 6. Om een element van een tupel aan te spreken gebruiken we de naam van de tupel, gevolgd door het volgnummer van het element, tussen vierkante haken. print(regenboog[2]) # 'geel' Een tupel kan alle soorten variabelen bevatten. allegaartje = (15, 'woef', True, 'miauw') Een tupel kan zelfs andere tupels bevatten, als dat nuttig zou zijn: verzamelingVanTupels = (allegaartje, regenboog) Je kan ook informatie opvragen over een tupel, zoals de lengte (het aantal elementen) of de positie van een bepaald element, maar dat werkt net op dezelfde manier als bij lijsten, dus laten we eerst kijken hoe die precies in elkaar zitten.. Lijsten Zoals gezegd kan de inhoud van een tupel niet meer wijzigen. Als we dus een boodschappenlijstje willen bijhouden is een tupel uitermate ongeschikt. Want als we vandaag ‘melk’, ‘brood’ en ‘choco’ op ons lijstje zetten, en we denken er morgen aan dat we ook nog ‘corn flakes’ moeten meenemen, dan kunnen we dat niet meer toevoegen aan onze tupel. Daar dienen lijsten dus voor. Lijsten (lists) in Python is wat in andere programmeertalen gekend is als arrays, en de werking is net hetzelfde als die van tupels, maar aan de inhoud van lijsten kunnen we wél nog wijzigingen aanbrengen. Om een lijst te maken schrijven we de elementen niet tussen ronde haken (zoals bij tupels) maar tussen vierkante haken. boodschappen = ['melk', 'brood', 'choco'] Python [12] Tupels, lijsten en woordenboeken versie 12/03/2015 2/8 Lijstfuncties Tijd om wat bewerkingen te doen op onze boodschappenlijst! Want we willen graag nog wat dingen toevoegen aan ons lijstje, we willen tellen hoeveel er op ons lijstje staat, en we willen uiteindelijk een gesorteerd lijstje uitprinten voor we naar de winkel gaan. Een eerste functie is de len() functie (we kennen hem nog van bij de strings), waarmee ik kan opvragen hoeveel zaken er al op mijn lijst staan. Deze functie werkt ook voor tupels en woordenboeken. len(boodschappen) len(regenboog) # 3 # 7 Drie dingen op mijn lijstje. Daar mag gerust nog wat meer op. Om een item toe te voegen aan het lijstje, gebruiken we de append() functie. Die plakken we aan de naam van onze lijst, met een puntje ertussen: boodschappen.append('corn flakes') De corn flakes staan nu mee op ons lijstje! Kijk maar na: print(boodschappen[3]) append() aanvaardt maar één toevoeging tegelijk. Als we dus zouden proberen om 2 zaken aan ons lijstje toe te voegen met boodschappen.append('waspoeder', 'gehakt') dan krijgen we een foutmelding van Python. Als we ineens meerdere zaken willen toevoegen, dan gebruiken we de extend() functie. Bij extend() zet je tussen haakjes een tupel of een lijst, en die wordt dan integraal toegevoegd aan je lijst. Dus om waspoeder en gehakt toe te voegen aan het lijstje, kunnen we bv. schrijven: boodschappen.extend(['waspoeder', 'gehakt']) Je mag in de extend() functie ook de naam van een andere lijst opgeven. Als je bv. je eigen lijstje bijhoudt, en je wil dat je mama dat toevoegt aan de grote boodschappenlijst, dan kan je schrijven: mijnlijstje = ['snoep', 'kinder surprise', 'kauwgom', 'choco'] boodschappen.extend(mijnlijstje) Gelukt! Maar… stond choco niet al op ons lijstje? En staat dat er nu niet twee keer op? Dat kunnen we controleren door aan Python te vragen hoeveel keer ‘choco’ voorkomt op het lijstje. Dat doen we met count(). boodschappen.count('choco') # 2 Python antwoordt ‘2’, dus choco staat 2 keer op ons lijstje. Om de dubbel te verwijderen gebruiken we de remove() functie. Met deze functie kan je een item van je lijst schrappen. Python gaat op zoek in het lijstje en zal de eerste vermelding die hij tegenkomt, schrappen. Python [12] Tupels, lijsten en woordenboeken versie 12/03/2015 3/8 We schrappen dus choco uit het lijstje (maar één keer choco blijft nog staan) en mama was het niet akkoord met de kauwgom op het lijstje, dus die vliegt er ook van. boodschappen.remove('choco') boodschappen.remove('kauwgom') Een andere manier om een item van een lijst te schrappen is met de pop() functie. In tegenstelling tot remove() moet je bij pop() niet de inhoud van het item opgeven dat je wil schrappen, maar het volgnummer. Dus met boodschappen.pop(1) schrappen we het 2de element van onze lijst (‘brood’). Voor het element effectief geschrapt wordt, geeft de pop()-functie de waarde van het geschrapte element (‘brood’ dus) nog terug als return-waarde. Wat returnwaarden zijn leer je in fiche [14] Je kan dus een element schrappen en het geschrapte element in een variabele opslaan via: geschrapt = boodschappen.pop(1) Wil je het volgnummer van een element opzoeken, dan kan je de index()-functie gebruiken. boodschappen.index('snoep') # 4 Wil je ergens een element tussenvoegen, dan kan dat ook, dankzij de insert()-functie. We willen bijvoorbeeld vóór het derde element (= volgnummer 2) een boodschap tussenvoegen: boodschappen.insert(2, 'kaas') Alle elementen schuiven nu een plaatsje op. ‘kaas’ zal nu het volgnummer 2 hebben. Om 2 lijsten samen te voegen hebben we geen speciale functie nodig – daarvoor kunnen we gewoon de + operator gebruiken. poeder = ['bloem', 'suiker'] vetstof = ['boter', 'eieren'] cake = poeder + vetstof print(cake) # ['bloem', 'suiker', 'boter', 'eieren'] Ook de * operator kunnen we gebruiken bij lijsten, om de inhoud van een lijst enkele keren te laten herhalen: eentweedrie = 3 * [1, 2, 3] print(eentweedrie) # [1, 2, 3, 1, 2, 3, 1, 2, 3] Python [12] Tupels, lijsten en woordenboeken versie 12/03/2015 4/8 Het is stilaan tijd om naar de winkel te gaan! We willen dus een gesorteerd boodschappenlijstje weergeven. Om te sorteren kan je de sort() functie gebruiken – daardoor wordt de lijst alfabetisch gesorteerd. boodschappen.sort() print(boodschappen) De alfabetisch gesorteerde lijst is nu onze nieuwe inhoud van de variabele ‘boodschappen’. We zijn onze oorspronkelijke volgorde dus kwijt. Wat als we eigenlijk ons lijstje niet wilden gesorteerd opslaan, maar alleen maar een afdruk wilden maken van de gesorteerde lijst, en de variabele ‘boodschappen’ ongemoeid wilden laten? Dan kunnen we de functie sorted() gebruiken. Die geeft een gesorteerde versie van de lijst weer, en verandert niets aan de eigenlijke variabele. print(sorted(boodschappen)) Nog een laatste functie in verband met sortering: reverse() – die functie draait het lijstje gewoon volledig om. Het laatste element wordt het eerste en omgekeerd. boodschappen.reverse() Als we terugkomen van de winkel is het tijd om het lijstje leeg te maken en met een nieuw lijstje te beginnen. Een lijst leegmaken doen we met de functie clear(). boodschappen.clear() Opmerking: len(), .count(), .index() en sorted() werken ook voor tupels. De andere functies uiteraard niet, omdat er aan de inhoud van een tupel niets kan veranderd worden. Python [12] Tupels, lijsten en woordenboeken versie 12/03/2015 5/8 Strings zijn eigenlijk tupels In de leerfiche over strings hadden we het al kort even vermeld: dat een string eigenlijk een lijst met letters is. Wel, dat mag je letterlijk nemen, want intern houdt Python de string eigenlijk bij als een tupel (wat uiteindelijk een variant van een lijst is). Het grappige daaraan is dat je ook een aantal van de lijstfuncties kan gebruiken op strings. len() hadden we al gebruikt om de lengte van een woord te kennen, maar je kan bv. ook tellen hoeveel keer een bepaalde letter voorkomt, je kan de notatie met vierkante haken gebruiken om een deel van een string weer te geven letterlijst = 'Monty Python' len(letterlijst) # 12 letterlijst.count('o') # 2 print(letterlijst[4]) # 'y' Net zoals bij tupels kan je een aantal functies niét gebruiken op strings, zoals .pop(), .append() en .extend(). Ook sort() kan je niet gebruiken, maar met sorted() kan je wel een alfabetische oplijsting van de inhoud van je string maken: sorted(letterlijst) # [' ', 'M', 'P', 'h', 'n', 'n', 'o', 'o', 't', 't', 'y', 'y'] Als je per se je string naar een lijst wil omzetten, kan dat met het list()-commando. lijst_met_letters = list(letterlijst) Delen van lijsten tonen Zoals je net geleerd hebt vertonen lijsten en strings wel erg veel gelijkenissen met elkaar. De notatiewijze die we gebruikten om een deel van een string te tonen werkt ook met lijsten (en tupels). huisdieren = ['hond', 'poes', 'hamster', 'rat', 'kip'] # Vanaf 4de element tot einde: print(huisdieren[3:]) # ['rat', 'kip'] # Vanaf derde element tot het vierde: print(huisdieren[2:4]) # ['hamster', 'rat'] # De eerste drie elementen: print(huisdieren[:3]) # ['hond', 'poes', 'hamster'] Python [12] Tupels, lijsten en woordenboeken versie 12/03/2015 6/8 Woordenboeken Er is nog een lijst-type dat we nog niet vermeld hebben: woordenboeken. Lijsten zijn heel handig, maar soms is het vervelend dat we de verschillende elementen alleen maar kunnen aanspreken aan de hand van de volgnummers. Als we bv. ons weekmenu op een lijstje willen bijhouden, dan zou het handig zijn als we zowel de dag als de maaltijd kunnen bijhouden in een element. maandag: Pasta dinsdag: Frietjes woensdag: Gehaktballetjes donderdag: Veggie vrijdag: Vis Dan kan met een woordenboek. Om een woordenboek aan te maken schrijven we de elementen tussen accolades (krulhaken). Per element schrijven we een sleutel, een dubbele punt en een waarde. naam_woordenboek = {'sleutel': 'waarde'} Ons weekmenu kunnen we bv. zo definiëren: menu = {'maandag': 'Pasta', 'dinsdag': 'Frietjes', 'woensdag': 'Gehaktballetjes', 'donderdag': 'Veggie', 'vrijdag': 'Vis'} En dan kunnen we snel en makkelijk het menu van een dag opvragen door de sleutel tussen vierkante haken te zetten: print(menu['dinsdag']) # Frietjes Op dezelfde manier kunnen we ook elementen toevoegen aan ons woordenboek: menu['zaterdag'] = 'Macaroni' De meeste lijstfuncties werken niet met woordenboeken. Je kan wel len() gebruiken om het aantal elementen te tellen. len(menu) Python [12] Tupels, lijsten en woordenboeken # 6 versie 12/03/2015 7/8 Ranges Er is nog een heel speciaal lijst-type waar we het over willen hebben: de range (= reeks). Een range is een reeks opeenvolgende getallen. We gaan dit vooral nuttig kunnen gebruiken als we in de volgende leerfiche iets leren over for-loops. De eenvoudigste range is die waar we één getal opgeven: het aantal getallen dat in de reeks moet voorkomen. En traditiegetrouw begint Python bij 0. range(4) # 0, 1, 2, 3 We kunnen als we willen ook de beginwaarde opgeven. Dan geven we eerst de beginwaarde op, en als tweede getal het getal waar de reeks onder moet blijven. range(1,5) # 1, 2, 3, 4 Drie getallen opgeven kan ook. Dan bepalen we de stapgrootte. Standaard verhoogt een reeks per stap met 1, maar we kunnen de reeks ook sneller laten oplopen. range(2,11,2) # 2, 4, 6, 8, 10 We kunnen de reeks zelfs laten aflopen, als we bv. -1 opgeven als stap. range(10,0,-1) # 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 Een range is een heel speciaal datatype, en je kan er de meeste lijstfuncties niet op toepassen. Wil je toch per se een range omzetten naar een bewerkbare lijst, dan kan dat met het list() commando. list(range(6)) En er zijn nog types… Er bestaan nog lijst-types in Python. We hebben je bijvoorbeeld nog niets verteld over een set. Maar dat zijn al meer gespecialiseerde lijsttypes die wij niet direct nodig gaan hebben. Ze komen in deze leerfiches dus verder niet aan bod. Python [12] Tupels, lijsten en woordenboeken versie 12/03/2015 8/8 Oefeningen Maak een programma waar je drie keer aan de gebruiker vraagt om een favoriete film op te geven. Voeg de films een voor één voor één toe aan een lijst, en sorteer die lijst dan. Geef de gesorteerde lijst weer op het scherm. Tip: om een lege lijst te maken kan je bv. het list() commando gebruiken. Zorg nu dat de lijst uit de vorige oefening gesorteerd is in omgekeerde alfabetische volgorde. Hoe pak je dit aan? Maak een lijst met alle even getallen die kleiner zijn dan 100. Denk na over hoe je die lijst gaat maken – zorg dat je niet al die getallen moet intypen. Maak vervolgens een lijst met alle oneven getallen die kleiner zijn dan 100. Voeg de twee lijsten dan samen in een nieuwe lijst, en sorteer de lijst. Als alles goed is heb je nu (op een heel omslachtige manier) een lijst met alle getallen die kleiner zijn dan 100. In deze leerfiche hebben we alleen maar geleerd hoe je een lijst alfabetisch kan sorteren. Voor ons boodschappenlijstje is dat eigenlijk niet zo zinvol. Het is beter om de boodschappen te sorteren volgens hun plaats in de winkel. Maar daarvoor hebben we functies nodig. Op de leerfiche over functies volgt er dus een (gevorderde) oefening over het sorteren van lijsten in een speciale volgorde. Python [12] Tupels, lijsten en woordenboeken versie 12/03/2015 9/9 [13] Rondjes draaien (loops) Met de if … else uit de leerfiche [11] hebben we leren werken met één van de belangrijkste programmeerstructuren in Python. Bijna even belangrijk zijn de verschillende mogelijkheden om herhalingslussen te maken in Python. Herhalingslussen worden ook wel eens loops (spreek uit: loeps) genoemd in het Engels. Er zijn twee soorten loops: lussen die een bepaald aantal keer moeten uitgevoerd worden (bv. “herhaal 7 keer”) en lussen die moeten uitgevoerd worden zolang een voorwaarde waar is (bv. “herhaal zolang de gebruiker geen ‘stop’ getypt heeft”). De lussen die een bepaald aantal keer moeten uitgevoerd worden zijn for-lussen, de voorwaardelijke lussen zijn while-lussen. for Volg mee via 13_For.py In Scratch hadden we een heel makkelijke manier om iets bijvoorbeeld 10 keer te herhalen. Dat deden we met het “herhaal … maal” blok: Zo’n herhalingsblokje ziet er in Python zo uit: for i in range(10): print('Dit wordt 10 keer op het scherm geschreven') We ontleden het commando even: for … in: dit is het commando waarmee we loops gaan bepalen die een bepaald aantal keer moeten uitgevoerd worden i: bij een for-lus moeten we verplicht een variabele opgeven die de waarde van de ‘index’ bijhoudt. Zometeen meer daarover. Voorlopig doen we nog niets met die variabele, maar er moet wel iets staan. range(10): we hebben in de vorige leerfiche geleerd wat een range is. Hier zorgt range(10) er voor dat de lus exact 10 keer wordt uitgevoerd. na het for-commando komt een dubbele punt, en daarna schrijven we de commando’s die binnen de lus moeten uitgevoerd worden, met een insprong (4 spaties of een tab). In de vorige leerfiche stond een oefening waarin er gevraagd werd om 3 keer aan de gebruiker van het programma te vragen om een favoriete film op te geven, en die daarna in een lijst te zetten. Met het forcommando kunnen we dat heel makkelijk doen, zonder dat we code dubbel moeten schrijven. Python [13] Rondjes draaien (loops) versie 12/03/2015 1/5 favoriete_films = list() for i in range(3): keuze_van_gebruiker = input('Geef een favoriete film op: ') favoriete_films.append(keuze_van_gebruiker) print('Je favoriete films in alfabetische volgorde: ', end='') print(sorted(favoriete_films)) Als we dit programma uitvoeren, krijgen we drie keer een vraag, en daarna verschijnt het volgende: Je favoriete films in alfabetische volgorde: ['Big Hero 6', 'Cars', 'Frozen'] Dat is al mooi, maar het lijstje met films kan echt wel nog mooier getoond worden. Het zou leuk zijn als we voor elk element van onze lijst een print-commando kunnen uitvoeren. Een for-lus kunnen we ook gebruiken om door een tupel, een lijst of een woordenboek te lopen: Als we de laatste 2 regels van ons vorige programma vervangen door: print('Je favoriete films in alfabetische volgorde:') for film in favoriete_films: print('-', film) Dan verschijnt ons lijstje als volgt: Je favoriete films in alfabetische volgorde: - Frozen - Cars - Big Hero 6 In deze for-lus (for film in favoriete_films) gebruiken we geen range om te bepalen hoeveel keer de lus moet uitgevoerd worden, maar gebruiken we de lijst ‘favoriete_films’. De lus zal dus even veel keer uitgevoerd worden als er elementen in de lijst zijn. Elke keer de lus uitgevoerd wordt, wordt het volgende elementje op de lijst tijdelijk in de variabele gestoken die we opgeven in ons for-commando. In dit geval vertellen we aan Python dat de variabele ‘film’ iedere keer de volgende film op het lijstje moet bevatten. Daarom zal print(film) iedere keer iets anders opleveren. index bij een for-loop De variabele die we opgeven om door een lus te lopen wordt ook wel eens de index genoemd. Daarom dat je zal zien dat nogal vaak de letter i gebruikt wordt als index, maar dit is niet verplicht. Helemaal aan het begin van deze leerfiche hebben we al een index i opgegeven: for i in range(10): print('Dit wordt 10 keer op het scherm geschreven') Maar in die lus hebben we de index niet gebruikt. We hebben gewoon 10 keer hetzelfde zinnetje op het scherm geschreven. Python [13] Rondjes draaien (loops) versie 12/03/2015 2/5 We veranderen een klein beetje aan de code: for i in range(10): print('Dit is zinnetje', i) Kan je zelf bedenken wat er verschijnt? De lus wordt 10 keer uitgevoerd, en bij elke lus neemt i de waarde aan van het volgende elementje in de range. Python begint te tellen bij 0, dus er verschijnt: Dit Dit Dit Dit Dit Dit Dit Dit Dit Dit is is is is is is is is is is zinnetje zinnetje zinnetje zinnetje zinnetje zinnetje zinnetje zinnetje zinnetje zinnetje 0 1 2 3 4 5 6 7 8 9 while Een for-lus is uitstekend geschikt om een lus een bepaald aantal keer uit te voeren. Maar soms willen we een lus blijven uitvoeren tot een bepaalde voorwaarde waar is: o o o Raadspelletje: blijf vragen om een getal te raden tot het ingevulde getal gelijk is aan het getal dat moet geraden worden. Wekker: blijf wachten om muziek te spelen tot het even laat is als het opgegeven wekker-uur Programma om lijstje met films op te geven: blijf films toevoegen aan een lijst tot de gebruiker ‘stop’ typt. Een voorwaardelijke lus in Python is een while-lus. While betekent ‘Terwijl’. We vertellen dus aan Python dat hij iets moet blijven doen terwijl een bepaalde voorwaarde waar is. Bekijk onderstaande code even. Python [13] Rondjes draaien (loops) versie 12/03/2015 3/5 Volg mee via 13_While.py films = list() # Maak een lege lijst # Nu maken we eerst een variabele om bij te houden # of we moeten blijven vragen naar films blijfVragenNaarFilms = True # Zolang deze True is moet je blijven vragen naar favoriete films while blijfVragenNaarFilms: favorieteFilm = input('Geef een favoriete film op. Typ STOP om te stoppen: ') if favorieteFilm == 'STOP': # De gebruiker heeft STOP getypt - de lus mag niet meer uitgevoerd worden blijfVragenNaarFilms = False else: # De gebruiker heeft een film opgegeven - voeg deze toe: films.append(favorieteFilm) # Nadat de gebruiker gestopt is, moeten we het lijstje laten zien print('Dit zijn je favoriete films:') for film in sorted(films): # We doorlopen de alfabetische lijst met films print('- %s' % film) In dit programma brengen we al een paar dingen bijeen die we geleerd hebben: je ziet een if-elsestructuur, je ziet een for-lus om over een gesorteerde lijst te lopen, en je ziet while blijfVragenNaarFilms: om een voorwaardelijke lus te laten lopen. Zo’n while-lus kan er soms heel compact uit zien. Bij een raad-spelletje zou de while-lus er bv. als volgt kunnen uit zien: from random import randint teRadenGetal = randint(1,20) while int(input('Raad een getal van 1 tot 20: ')) != teRadenGetal: print('Fout!') print('Getal geraden!') De from random import randint en de randint(1,20) zorgen ervoor dat Python een willekeurig getal tussen 1 en 20 kiest. Snap je de rest van de code? Python [13] Rondjes draaien (loops) versie 12/03/2015 4/5 break en continue Volg mee via 13_BreakContinue.py In het voorbeeldje met het opvragen van de favoriete films hebben we een beetje een complexe structuur gebruikt om te zorgen dat Python bleef films vragen tot de gebruiker STOP typte. Die zag er ongeveer zo uit: 1. Ga er van uit dat je moet blijven vragen om een film tot ik zeg dat je het niet meer hoeft te doen. 2. Zolang je moet blijven vragen om een film, doe je het volgende: a. Vraag een film. b. Als de gebruiker STOP getypt heeft mag je zometeen stoppen met het vragen van films. c. Als de gebruiker geen STOP getypt heeft, voeg dan zijn gekozen film toe aan het lijstje d. Ga nu terug naar stap 2 3. Als je niet meer om een film moet vragen, is het tijd om het lijstje te sorteren en te tonen. Dankzij de variabele blijfVragenNaarFilm houden we netjes bij of de lus de volgende keer nog moet uitgevoerd worden of niet, maar de lus waarin we zitten voeren we wel netjes tot het eind uit. Dat is een heel nette manier van gestructureerd programmeren, maar dat is niet altijd de kortste manier om te programmeren. Soms is het makkelijker om als volgt te werk te gaan: 1. Blijf eindeloos vragen om een film: a. Vraag een film b. Als de gebruiker STOP getypt heeft, stop dan onmiddellijk met deze lus c. Voeg wat de gebruiker getypt heeft toe aan het lijstje. 2. Sorteer het lijstje en toon het Dat is een stuk korter (maar minder gestructureerd) dan het eerste scenario, en dat ziet er zo uit in Python: films = list() # Maak een lege lijst while True: # Voer eindeloos uit favorieteFilm = input('Geef een favoriete film op. Typ STOP om te stoppen: ') if favorieteFilm == 'STOP': # De gebruiker heeft STOP getypt - de lus moet ONMIDDELLIJK stoppen break films.append(favorieteFilm) # Laat het lijstje zien print('Dit zijn je favoriete films:') for film in sorted(films): print('- %s' % film) Zodra Python break uitvoert, wordt de lus afgebroken en wordt er verder gegaan met de rest van het programma. We hebben dus geen booleaanse variabele nodig om bij te houden of de lus nog moet uitgevoerd worden. Python [13] Rondjes draaien (loops) versie 12/03/2015 5/5 Er is ruimte voor nog één verbetering. Als de gebruiker nu op enter duwt zonder iets in te typen, dan wordt er gewoon een leeg element toegevoegd aan onze lijst met films. Dat is niet zo goed. Dat kunnen we oplossen door aan Python te zeggen dat de while-lus gewoon voorafaan moet herbegonnen worden zonder de rest uit te voeren als er niets is ingetypt. Dat doen we met het continue-commando: if favorieteFilm == '': # De gebruiker heeft gewoon op enter gedrukt - herbegin de lus! continue Als je bovenstaande code vooraan in de lus toevoegt (vóór je de film effectief toevoegt aan de lijst) zullen de lege regels netjes genegeerd worden. Samengevat - while: voert een lus uit zolang aan een voorwaarde voldaan is break: breekt een lus voortijdig af en gaat verder met de code na de lus continue: breekt een lus voortijdig af en herbegint de lus break en continue kunnen ook gebruikt worden in for-lussen. Oefeningen We hebben geleerd hoe je over een lijst kan lopen met een for-lus. Bedenk een manier om de elementen van een lijst te doorlopen door een for i in range(…) lus. In de vorige leerfiche hebben we over complexe ranges geleerd. Maak een for-lus waar je een range gebruikt die van groot naar klein gaat, en met tussenstappen die groter zijn dan 1. Als je een for-lus maakt met een range, gebruiken we het Python-keyword “in” (for i in range). Dit in-keyword kan ook gebruikt worden in combinatie met een if, om bv. te kijken of een bepaald getal zich in een bepaalde range bevindt, of als een bepaald element zich in een lijst bevindt. Probeer dit uit. Een lus die een bepaald aantal keer moet doorlopen worden maken we met het for-commando. Maar je kan dit eigenlijk ook met een while-lus. Maak een while-lus die exact 10 keer doorlopen wordt. Maak een raadspelletje. Bepaal een willekeurig getal tussen 0 en 100 en laat de gebruiker getallen raden. Geef telkens aan of zijn gokje groter is dan het te raden getal, of het kleiner is, of als het gelijk is. In dat laatste geval stopt het spel natuurlijk. Extra: hou als score ook bij hoeveel keer je erover hebt gedaan om het getal te raden. Python [13] Rondjes draaien (loops) versie 12/03/2015 6/6 [14] Functies Een goede programmeur doet altijd zijn best om zoveel mogelijk aan hergebruik van code te doen. Je probeert in je programma code te gebruiken die iemand anders heeft gemaakt, of code die je zelf eerder al eens hebt gemaakt. Het gebruik van functies (en later van klasses) is daarbij essentieel. Volg mee via 14_Functies-1.py We beginnen met een eenvoudig voorbeeldje: De opzet van het programma is heel eenvoudig. Er staan 7 minions op een rij. We vragen aan de gebruiker om een minion te kiezen, en dat laten we zien wat de minion zegt. Elke minion zegt iedere keer hetzelfde, maar er zijn maar 3 verschillende zinnetjes die ze uitspreken. Poging 1 om dit in een programma te zetten: keuze = int(input('Er zijn 7 minions. Welke minion wil je horen spreken? (1-7): ')) if keuze == 1: print('De minion print('De andere elif keuze == 2: print('De minion print('De andere elif keuze == 3: print('De minion print('De andere elif keuze == 4: print('De minion print('De andere elif keuze == 5: print('De minion print('De andere elif keuze == 6: print('De minion print('De andere elif keuze == 7: print('De minion print('De andere Python [14] Functies zegt BANANA!') minions trekken aan zijn bril.') zegt Para Tuu!') minions trekken aan zijn bril.') zegt BANANA!') minions trekken aan zijn bril.') zegt Bie-Doe Bie-Doe!') minions trekken aan zijn bril.') zegt Bie-Doe Bie-Doe!') minions trekken aan zijn bril.') zegt BANANA!') minions trekken aan zijn bril.') zegt Para Tuu!') minions trekken aan zijn bril.') versie 12/03/2015 1/5 Dit programma werkt zoals het moet werken, maar het is hele slechte code. Er wordt heel veel hetzelfde herhaald, en als we op een dag dus beslissen dat het tweede zinnetje niet moet gaan over minions die aan de bril trekken maar wel over de banaan die ze eten, dan moeten we élk van die regeltjes aanpassen. Functies = herbruikbare code Dat kan dus veel efficiënter. We gaan op zoek naar de code die meerdere keren voorkomt, en we steken die code in aparte functies. Er zijn 4 zinnetjes die regelmatig terugkomen: - De minion zegt BANANA! De minion zegt Para Tuu! De minion zegt Bie-Doe Bie-Doe! De andere minions trekken aan zijn bril. Die 4 zinnetjes steken we in een functie – we definiëren een functie met het def-keyword: Volg mee via 14_Functies-2.py def banana(): print('De minion brilletjeTrek() def paratuu(): print('De minion brilletjeTrek() def biedoe(): print('De minion brilletjeTrek() def brilletjeTrek(): print('De andere zegt BANANA!') zegt Para Tuu!') zegt Bie-Doe Bie-Doe!') minions trekken aan zijn bril.') Nu we bv. de functie banana() gedefinieerd hebben, kunnen we deze in de code gewoon aanroepen met het commando banana(): keuze = int(input('Er zijn 7 minions. Welke minion wil je horen spreken? (1-7): ')) if keuze == 1: banana() if keuze == 2: paratuu() if keuze == 3: banana() if keuze == 4: biedoe() if keuze == 5: biedoe() if keuze == 6: banana() if keuze == 7: paratuu() Dat ziet er al een stuk efficiënter uit! Maar het kan nog beter. Python [14] Functies versie 12/03/2015 2/5 Functie-argumenten (parameters) Overal waar een functie aangeroepen wordt, wordt de code van de functie “ingeplakt” in het programma. Maar tussen de functies onderling is er nog heel wat gedeelde code. Elk van de functies banana(), paratuu(), biedoe() beschijft wat een minion zegt – enkel het woordje dat ze uitspreken is verschillend. We kunnen onze vier functies dus samen nemen in één functie als we bij de functie-aanroep (vanuit het programma) opgeven over wélk woordje het precies gaat. Dat doen we met functie-parameters, die we tussen haakjes zetten. Zo ziet onze nieuwe functie er uit: Volg mee via 14_Functies-3.py def minionZegt(wat): print('De minion zegt', wat) print('De andere minions trekken aan zijn bril.') Tussen haakjes zetten we de variabele ‘wat’, die we dan kunnen gebruiken binnen onze functie. Vanuit ons programma ziet de functie-aanroep er dan zo uit: minionZegt('BANANA!') Binnen die specifieke uitvoering van de functie neemt de parameter ‘wat’ dus de waarde ‘BANANA!’ aan. Ons eigenlijke programma ziet er dan zo uit: keuze = int(input('Er zijn 7 minions. Welke minion wil je horen spreken? (1-7): ')) if keuze == 1: minionZegt('BANANA!') if keuze == 2: minionZegt('Para Tuu!') if keuze == 3: minionZegt('BANANA!') if keuze == 4: minionZegt('Bie-Doe Bie-Doe!') if keuze == 5: minionZegt('Bie-Doe Bie-Doe!') if keuze == 6: minionZegt('BANANA!') if keuze == 7: minionZegt('Para Tuu!') Da’s alweer een pak beter! Maar het kan nóg beter! Python [14] Functies versie 12/03/2015 3/5 return-waarden Want nu hebben we al een functie om de minion iets te laten “zeggen”, maar hoe laten we de minion bijvoorbeeld iets roépen? Moeten we daar dan een aparte functie voor schrijven? In programmeertalen wordt dat probleem opgelost door functies een bepaalde waarde te laten teruggeven (return), en in het hoofdprogramma bepalen we dan wat we met die teruggegeven waarde doen. Een functie moet je eigenlijk zien als een soort machine waar we langs de ene kant iets insteken, en waar er langs de andere kant iets uit komt. Een koffiezetapparaat bijvoorbeeld – de ingevoerde parameters zijn water en koffiepoeder, en de return-waarde van de functie is de koffie. Maar we beslissen zelf of we die in een beker of een kopje doen. We gaan voor onze minions dus een functie maken die enkel en alleen bepaalt wàt de minions zeggen, en die waarde ook teruggeeft aan het hoofdprogramma. In het hoofdprogramma bepalen we dan zelf wat we met die waarde doen: zeggen, roepen, fluisteren, … We maken van de gelegenheid ook gebruik om het aantal if’jes te verminderen: we bepalen een tupel met de nummers van de minions die BANANA! zeggen (1, 3 en 6), en met het in-keyword checken we of de keuze een van de getallen uit die tupel is. Ons afgewerkte en geoptimaliseerde programma ziet er zo uit: Volg mee via 14_Functies-4.py def watZegtMinion(wie): if wie in (1,3,6): return 'BANANA!' elif wie in (2,7): return 'Para Tuu!' elif wie in (4,5): return 'Para Tuu!' else: return 'niets!' # HOOFDPROGRAMMA # keuze = int(input('Er zijn 7 minions. Welke minion wil je horen spreken? (1-7): ')) stopwoordje = watZegtMinion(keuze) print('De minion zegt', stopwoordje) print('De minion roept', stopwoordje) print('De minion schreeuwt', stopwoordje) print('De andere minions trekken aan zijn bril.') Een hele verbetering tegenover het programma waarmee we begonnen zijn, nietwaar? In ieder geval véél flexibeler, en veel makkelijker aan te passen. We hoeven trouwens geen variabelen te gebruiken om de return-waarde van onze functie tijdelijk in op de slaan. Als we de minion alleen maar iets willen laten “zeggen” kunnen we bv. ons hoofdprogramma een stuk compacter maken op deze manier: Python [14] Functies versie 12/03/2015 4/5 # Nog compacter HOOFDPROGRAMMA # print('Hij zegt', watZegtMinion(int(input('Er zijn 7 minions. \ Welke minion wil je horen spreken? (1-7): ')))) Eigenlijk gebruiken jullie al een hele tijd functies, parameters en return-waarden. Als we bv. schrijven: getal = int(tekst) gesorteerdeLijst = sorted(lijst) dan zijn we de ingebouwde functies van Python aan het gebruiken: - Steek in de variabele “getal” de return-waarde van de functie “int” met als parameter “tekst” Steek in de variabele “gesorteerdeLijst” de return-waarde van de functie “sorted” met als parameter “lijst” Samenvatting Om nog even samen te vatten vergelijken we functies nog even met een manier om een drankje te krijgen. - Een functie zonder parameters en zonder return-waarde voert gewoon een stuk code uit. Bv. de functie brengMijKoffie() waarmee je iemand vraagt om je een tas koffie te brengen in een beker en deze voor je neus te zetten. - Een functie zonder parameters maar mét een return-waarde laat je toe om te bepalen wat je met het resultaat doet. Bv. de functie beker = maakKoffie() staat gelijk aan een koffie-automaat met één knop (je kan dus niet kiezen wat je er in doet), maar je kiest wel waar je koffie terecht komt: in je beker, in een kopje of in een puntzak, wat dat betreft. - Een functie mét parameters maar zonder return-waarde laat je bepalen met welke "ingrediënten" een functie zal werken, maar niet wat de functie met het resultaat doet. Bv. een koffie-automaat waar je het sóórt koffie wel kan kiezen, maar waarbij je koffie àltijd in een bekertje afgeleverd wordt, kunnen we aansturen met maakKoffie(cappucino). - Een functie mét parameters en mét return-waarde laat je bepalen wat de functie doet en met welke waarden hij dat doet, en laat je ook bepalen wat je met het resultaat doet. Bv. de functie beker = maakDrank(koffiepoeder, water) is een drankenmachine die aan de slag gaat met de 2 ingrediënten die je opgeeft. In dit geval maken we koffie, maar met dezelfde functie (= machine) met andere argumenten maken we bv. chocomelk: glas = maakDrank(chocopoeder, melk) Python [14] Functies versie 12/03/2015 5/5 Oefeningen Schrijf een functie die een naam aanvaardt als parameter, en die een begroeting op het scherm laat verschijnen zodra de functie aangeroepen wordt. De return-waarde van een functie kan om het even welke variabele zijn. Het kan dus een booleaanse variabele zijn, een integer, een string, … maar het kan even goed een lijst of een tupel zijn. Je kan dus méérdere waarden meegeven als return-waarde van een functie, door ze in een tupel te steken. Probeer dit uit door een functie te schrijven die van een opgegeven woord de eerste en de laatste letter teruggeeft. Je kan ook een lijst of een tupel als parameter van een functie aanvaarden. Schrijf een functie die een reeks getallen aanvaardt als input, en die de kleinste waarde, de grootste waarde en de gemiddelde waarde teruggeeft. Een oefening voor gevorderden: we breien verder op een oefening uit leerfiche [12] Daar hebben we een programma gemaakt waar we onze boodschappen konden opgeven, en we kregen een alfabetisch boodschappenlijstje als resultaat. Alfabetische boodschappenlijstjes zijn niet zo nuttig als je in een winkel staat waar de producten niet alfabetisch gesorteerd zijn. Maak nu een programma waarbij je boodschappen kan intypen, en een lijstje terugkrijgt dat gesorteerd is volgens de schikking in de winkel. Om dit op een vereenvoudigde manier te doen, ga je als volgt te werk: o Maak vooraf een lijst met bv. een 20-tal producten waaruit mag gekozen worden. o Maak een functie waarbij je in de functie elk van die producten in een productcategorie steekt, bv. drogeVoeding = ['koekjes', 'corn flakes ', 'beschuit'] o Laat de functie voor elk van de boodschappen op je lijstje lopen, en bepaal binnen de functie binnen welke categorie het product valt. Je ziet zometeen hoe. o Geef als return-waarde voor de functie een getal terug. Het getal staat symbool voor de plaats van de productcategorie in de winkel. Als de wijn eerst staat, en de droge voeding daarna, dan geef je voor een wijn ‘1’ terug, en voor koekjes ‘2’. Voor corn flakes geef je eveneens ‘2’ terug. o Als het te moeilijk is om een getal terug te geven, kan je ook werken met namen van productcategorieën die beginnen met getallen. Bv.: 01-wijn, 02-droge voeding, … o Gebruik je functie en het resultaat in combinatie met de functie sorted(). Bij sorted() geef je als eerste parameter altijd je lijst op die je wil sorteren, maar kan je ook een ‘key’ parameter opgeven waarin je een functie kan benoemen. Alle elementen van de te sorteren lijst zullen dan aan de functie doorgegeven worden als parameter, en de return-waarden zullen gebruikt worden voor de sortering. Dus als je functie ‘categorieplaats’ heet, kan je met sorted(boodschappenLijst, key=categorieplaats) de lijst sorteren volgens categorie. De oplossing van de laatste oefening vind je in 14_Oefening.py Python [14] Functies versie 12/03/2015 6/6 [15] Variabelen in functies (of: een woordje over scope) In de vorige leerfiche hebben we geleerd over functies. We leerden dat functies parameters hebben en dat ze return-waarden kunnen teruggeven aan het hoofdprogramma. Maar hebben we die parameters en die return-waarden eigenlijk wel nodig? Is het niet makkelijker om variabelen gewoon rechtstreeks vanuit een functie aan te passen? Kijk bijvoorbeeld naar dit programma: def veranderNaam(nieuwenaam): naam = nieuwenaam # HOOFDPROGRAMMA # naam = 'Karel' print('Hallo', naam) veranderNaam('Thomas') print('Hallo', naam) In dit programma definieer ik een variabele ‘naam’ die ik eerst de waarde ‘Karel’ geef. Ik schrijf een begroeting op het scherm, en vervolgens verander ik de variabele ‘naam’ in ‘Thomas’, via de functie veranderNaam(). Daarna begroet ik opnieuw. Maar mijn programma mislukt. Dit verschijnt op het scherm: Hallo Karel Hallo Karel De functie veranderNaam() heeft met andere woorden onze variabele ‘naam’ niet veranderd. De schuld ligt bij de scope (of het bereik) van variabelen. Globale versus lokale variabelen Om te snappen wat er mis loopt, moeten we even bekijken hoe Python omgaat met variabelen in een programma en in functies. Op de volgende bladzijde staat een tekening die een programma voorstelt. Een programma draait in een bepaalde “ruimte” (in de tekening voorgesteld door een rechthoek), en in de ruimte van dat programma zijn er een aantal variabelen gedefinieerd. programaVariabele1, programmaVariabele2, programmaVariabele3 en programmaVariabele4 kunnen gelijk waar in het programma gebruikt worden. In het programma worden ook een aantal functies gedefiniëerd. Zoals je ziet op de tekening heeft de functie zijn eigen rechthoek gekregen. Een functie is een soort mini-programma, en dat mini-programma draait in zijn eigen wereldje. De variabelen die gedefinieerd zijn in een functie zijn énkel gekend in het kleine wereldje van die functie. Het zijn lokale variabelen. Python [15] Variabelen in functies (of: een woordje over scope) versie 12/03/2015 1/5 De variabelen functieVariabele1, functieVariabele2 en functieVariabele3 in de functie zijn dus énkel binnen die functie gekend. De functie heeft geen weet van wat er in het grote programma allemaal bestaat. Dus als ik binnen de functie met bv. programmaVariabele3 probeer te werken, zal dit niét de programmaVariabele3 uit het hoofdprogramma zijn. Hoe kunnen we dan gegevens uitwisselen tussen hoofdprogramma en functie? Op de manieren die we al geleerd hebben, en op een bijkomende manier: - waarden van variabelen uit het hoofdprogramma doorgeven aan een functie doen we via de parameters van de functie waarden van variabelen uit de functie doorgeven aan het hoofdprogramma doen we via de returnwaarden van de functie als bijkomende manier kunnen we een variabele in een functie eventueel als globaal definiëren. Daarmee vertellen we aan Python dat we eigenlijk de variabele uit het hoofdprogramma willen gebruiken. We keren even terug naar het programma uit het begin van deze fiche, en we voegen één regeltje toe aan de functie: def veranderNaam(nieuwenaam): global naam naam = nieuwenaam Via het regeltje global naam vertellen we aan Python dat we binnen de functie met de globale versie van ‘naam’ willen werken. En nu werkt ons programma wel zoals voorzien. Dus: het bereik (de scope) van een variabele is normaal gezien altijd lokaal – dat wil zeggen dat de variabele enkel gekend is binnen het wereldje van de functie – maar als we willen kunnen we ook werken met globale variabelen. Python [15] Variabelen in functies (of: een woordje over scope) versie 12/03/2015 2/5 Dat concept kennen jullie trouwens misschien nog uit Scratch. Kijk eens naar het kadertje dat je krijgt als je een nieuwe variabele maakt in Scratch: Zie je de selectie? “Voor alle sprites” of “Alleen voor deze sprite”. - “Voor alle sprites” wil zeggen dat je de variabele globaal definieert, en dat alle sprites gebruik kunnen maken van dezelfde variabele. “Alleen voor deze sprite” wil zeggen dat je de variabele lokaal definieert, en dat de andere sprites deze niet zullen kunnen gebruiken. Probeer globale variabelen te vermijden Het gebruik van het Python-keyword global kan een heel makkelijke manier lijken om met functies te werken in Python en om ervoor te zorgen dat je niet voortdurend met parameters en return-waarden moet werken, maar toch is overmatig gebruik ervan af te raden. We kunnen over het algemeen perfect zonder globale variabelen, als we maar een beetje nadenken over welke parameters we doorgeven en welke return-waarden we teruggeven. Een poging tot voorbeeld Hoewel we ver moeten zoeken om een béétje een goed voorbeeld van het gebruik van globale variabelen te vinden, doen we toch een poging. We willen een programma maken om een lijst met superhelden bij te houden. In de lijst met superhelden staat de gewone dagdagelijkse naam van de superheld, staat de superheldennaam van de held, en wordt er bijgehouden of ze momenteel verkleed zijn als mens of als ze verkleed zijn als superheld. Python [15] Variabelen in functies (of: een woordje over scope) versie 12/03/2015 3/5 We gaan een aantal functies definiëren om gemakkelijk de superheldenlijst te kunnen beheren: - een functie om een lege lijst aan te maken (te initialiseren) een functie om een persoon toe te voegen aan onze lijst een functie om de superheldenidentiteit van een persoon toe te voegen aan de lijst een functie om aan te geven dat een bepaald persoon zich verkleedt (van mens naar superheld en omgekeerd) een functie om de lijst te tonen van de superhelden en hoe ze momenteel verkleed zijn Als we bij al die functies de superheldenlijst die we opbouwen telkens zouden moeten doorgeven als returnwaarde en als parameter, wordt het een beetje omslachtig. Dus we gaan werken met een globale superheldenlijst, die in elke functie gekend is. Zo kan ons programma er dan uit zien: Volg mee via 15_Scope.py def maakLegeLijst(): global superheldenlijst superheldenlijst = dict() def voegPersoonToe(persoon, identiteit=''): # We voegen een persoon toe. # Standaard weten we niets over zijn superheldenidentiteit. global superheldenlijst superheldenlijst[persoon] = {'superheldenIdentiteit': identiteit, 'isSuperheld': False} def bepaalSuperheldenIdentiteit(persoon, identiteit): global superheldenlijst superheldenlijst[persoon]['superheldenIdentiteit'] = identiteit def verkleed(persoon): global superheldenlijst superheldenlijst[persoon]['isSuperheld'] = not superheldenlijst[persoon]['isSuperheld'] def toonlijst(): global superheldenlijst for persoon, kenmerken in superheldenlijst.items(): if kenmerken['superheldenIdentiteit'] != '': print('-', persoon, 'is momenteel', end=' ') if kenmerken['isSuperheld']: print(kenmerken['superheldenIdentiteit']) else: print('zichzelf') else: # Er is geen superheldenidentiteit bekend print('-', persoon, 'heeft geen superheldenidentiteit') Python [15] Variabelen in functies (of: een woordje over scope) versie 12/03/2015 4/5 # HOOFDPROGRAMMA # maakLegeLijst() voegPersoonToe('Peter Parker') voegPersoonToe('Clark Kent', 'Superman') bepaalSuperheldenIdentiteit('Peter Parker', 'Spiderman') voegPersoonToe('Piet Buyse') voegPersoonToe('Bruce Wayne', 'Batman') verkleed('Clark Kent') # word Superman verkleed('Bruce Wayne') # word Batman verkleed('Clark Kent') # word weer Clark Kent toonlijst() Als we het programma laten lopen krijgen we deze output: - Peter Parker is momenteel zichzelf Clark Kent is momenteel zichzelf Piet Buyse heeft geen superheldenidentiteit Bruce Wayne is momenteel Batman En tot daar het beste voorbeeld dat we konden verzinnen voor het gebruik van globale variabelen. En eigenlijk is het nog altijd een slecht voorbeeld, want het geval waarvoor we hier globale variabelen gebruiken vraagt eigenlijk veel meer om het gebruik van klasses en objecten dan om het gebruik van globale variabelen. Zodra we in leerfiche [19] over klasses en objecten leren, zullen we zien dat klasses en objecten een veel betere manier zijn om dit superheldenprogramma te maken. En met klasses zullen de mogelijkheden van ons programma groter zijn. Want wat als we bv. tegelijkertijd 2 verschillende superheldenlijsten willen bijhouden? Eén met slechteriken en één met de goeie? Hoe lossen we dàt op met ons globale-variabelenprogramma? (tip: niet) Standaardwaarden voor parameters Heb je iets speciaals opgemerkt aan de functie voegPersoonToe()? Kijk eens in het hoofdprogramma: de functie wordt daar op 2 manieren aangeroepen: voegPersoonToe('Peter Parker') voegPersoonToe('Clark Kent', 'Superman') De eerste keer voegen we gewoon een persoon toe, met één parameter. We geven de superheldenidentiteit nog niet op – we doen dat pas later in het programma met de functie bepaalSuperheldenIdentiteit(). De tweede keer (als we Clark Kent toevoegen) geven we wél direct zijn superheldenidentiteit op. We gebruiken dus plots twee parameters voor dezelfde functie. Hoe kan dat zonder dat Python een foutmelding geeft? Door het gebruik van standaardwaarden voor optionele parameters. Python [15] Variabelen in functies (of: een woordje over scope) versie 12/03/2015 5/5 Bekijk de definitie van de functie voegPersoonToe(): def voegPersoonToe(persoon, identiteit=''): # We voegen een persoon toe. # Standaard weten we niets over zijn superheldenidentiteit. global superheldenlijst superheldenlijst[persoon] = {'superheldenIdentiteit': identiteit, 'isSuperheld': False} Doordat we bij de tweede parameter direct een waarde opgeven (de lege string '') hebben we deze parameter als optioneel gemarkeerd. Ik mag dus kiezen of ik de parameter opgeef of niet. Geef ik niets op, dan wordt de opgegeven standaardwaarde gebruikt. Nog één voorbeeldje om het af te leren: def coderdojoIs(wat='supertof'): print('CoderDojo is', wat + '!') # HOOFDPROGRAMMA # coderdojoIs('megabangelijk') coderdojoIs() # CoderDojo is megabangelijk! # CoderDojo is supertof! De eerste keer roepen we de functie coderdojoIs() aan mét parameter, de tweede keer zonder. Bij de aanroep zonder wordt er ‘supertof’ als standaardwaarde gebruikt. Oefeningen Maak een programma waarin je een naam definieert. Roep vervolgens een functie begroet() aan (zonder parameters dus) waardoor er bv. “Hallo Xander” verschijnt (als de naam die je gedefinieerd hebt Xander is). Pas nu de functie aan, en zorg dat je optioneel een naam kan ingeven om te laten begroeten. Bekijk de functie toonlijst() uit het superheldenprogramma eens heel goed. Daar wordt een forlus gebruikt die je kan gebruiken in combinatie met een Python-woordenboek, om tegelijkertijd de namen van de elementen als de waarden te krijgen in je lus. Python [15] Variabelen in functies (of: een woordje over scope) versie 12/03/2015 6/6 [P1] Project: Raad een getal Vereiste voorkennis: tot en met fiche [7] Opdracht We maken een heel traditioneel raad-spelletje. De computer bepaalt een willekeurig getal tussen 1 en 100, en wij mogen een getal raden. De computer zegt of we hoger of lager moeten mikken. In gemiddeld een zevental keer raden moet je er zo in slagen om het getal te vinden. Wat hebben we nodig? - Een functie om een willekeurig getal te bepalen Een while-lus om een herhalingslus te laten draaien zolang we niet goed geraden hebben Enkele variabelen om het aantal raadpogingen bij te houden, en om via waar of onwaar bij te houden of we het getal al gevonden hebben of niet. Aan de slag! Volg mee via P1_RaadEenGetal.py We beginnen met het bepalen van ons willekeurig getal. Dat doen we via de functie randint() uit de bibliotheek “random”. Om de functie randint() te kunnen gebruiken beginnen we met de volgende regel: from random import randint # Zorg dat we willekeurige getallen kunnen bepalen En vervolgens bepalen we een getal tussen 1 en 100 (1 en 100 inclusief): teRadenGetal = randint(1,100) Nu kunnen we beginnen met het begroeten van onze gebruiker. Hiervoor gebruiken we een aantal simpele print-commando’s. print('Raadspelletje') print('-------------') print('Raad een getal tussen 1 en 100') print('') Nu bepalen we 2 variabelen. Eentje om bij te houden of het getal al geraden is of niet (en we beginnen bij “niet geraden”), en eentje om bij te houden hoeveel raadpogingen er al geweest zijn (we beginnen bij 0 en we verhogen bij elke raadpoging met 1). getalGeraden = False aantalKeerGeraden = 0 Python [P1] Project: Raad een getal versie 12/03/2015 1/2 Nu moeten we volgende code uitvoeren: - zolang het getal niet geraden is: o vraag een gokje o verhoog de teller o bekijk of het gokje kleiner, groter of gelijk is aan het te raden getal o als het gelijk is, stop dan de lus door getalGeraden gelijk te maken aan ‘waar’. In Python-code ziet dat er zo uit: while not getalGeraden: gokje = int(input('Wat is je gok? ')) aantalKeerGeraden += 1 # Verhoog de teller met 1 if gokje < teRadenGetal: print('Te laag! Probeer opnieuw.') elif gokje > teRadenGetal: print('Te hoog! Probeer opnieuw.') else: # Als het niet groter of kleiner is, is het gelijk print('Goed geraden! Je hebt er', aantalKeerGeraden, 'raadpogingen voor nodig gehad.') getalGeraden = True Dat is het – het programma is af. Een voorbeeld van het programma Zo ziet het afgewerkte programma er uit als we het laten lopen: Raadspelletje ------------Raad een getal tussen 1 en 100 Wat is je gok? 50 Te hoog! Probeer opnieuw. Wat is je gok? 25 Te laag! Probeer opnieuw. Wat is je gok? 35 Te laag! Probeer opnieuw. Wat is je gok? 40 Te hoog! Probeer opnieuw. Wat is je gok? 38 Te hoog! Probeer opnieuw. Wat is je gok? 36 Goed geraden! Je hebt er 6 raadpogingen voor nodig gehad. Python [P1] Project: Raad een getal versie 12/03/2015 2/2 De volledige code # Raad een getal from random import randint # Zorg dat we willekeurige getallen kunnen bepalen teRadenGetal = randint(1,100) # Begroeting print('Raadspelletje') print('-------------') print('Raad een getal tussen 1 en 100') print('') getalGeraden = False aantalKeerGeraden = 0 while not getalGeraden: gokje = int(input('Wat is je gok? ')) aantalKeerGeraden += 1 # Verhoog de teller met 1 if gokje < teRadenGetal: print('Te laag! Probeer opnieuw.') elif gokje > teRadenGetal: print('Te hoog! Probeer opnieuw.') else: # Als het niet groter of kleiner is, is het gelijk print('Goed geraden! Je hebt er', aantalKeerGeraden, 'raadpogingen voor nodig gehad.') getalGeraden = True Python [P1] Project: Raad een getal versie 12/03/2015 3/3 [P2] Project: Gekke zinnen Vereiste voorkennis: tot en met fiche [7] en best fiche [12] ook even doornemen. Opdracht We gebruiken de randint() functie (om willekeurige getallen te maken) om willekeurig woordjes uit lijsten te pikken en in gekke zinnen te plakken. We maken een lijst met namen, een lijst met werkwoorden en een lijst met naamwoorden, en laten het programma daar willekeurig uit kiezen. Wat hebben we nodig? - Enkele lijsten met namen, werkwoorden en naamwoorden Een functie om willekeurig een woord te kiezen Aan de slag Volg mee via P2_GekkeZinnen.py We beginnen met het bepalen van onze lijsten met namen, werkwoorden en naamwoorden. Bijvoorbeeld: naam = ['Bjarne', 'Jelle', 'Juul', 'Martijn', 'Matthias', 'Mauro', 'Michiel', 'Sybille', 'Victor', 'Wim', 'Xander'] werkwoord = ['koopt', 'rijdt met', 'zoekt', 'drinkt', 'speelt met', 'eet', 'kuist', 'schildert', 'maakt', 'kiest'] naamwoord = ['leeuw', 'fiets', 'vliegtuig', 'wasmand', 'horloge', 'schilderpalet', 'bloem', 'bal', 'eend', 'beer', 'dinosaurus', 'huis', 'ruimteschip', 'printer', 'machine', 'elektrische tandenborstel', 'sleutelgat', 'sleutel'] Vervolgens zorgen we ervoor dat we de functie randint() kunnen gebruiken. from random import randint Nu maken we een functie waarmee we uit een opgegegeven lijst een willekeurig woord kiezen. Dat doen we door eerst te bepalen hoeveel elementen er in de lijst zitten, en vervolgens een willekeurig rangnummer te bepalen. Het willekeurig woord wordt teruggegeven. def kies(woorden): aantal_woorden = len(woorden) woordnummer = randint(0, aantal_woorden - 1) gekozen_woord = woorden[woordnummer] return gekozen_woord Het enige wat we nu nog nodig hebben is een herhalingslus die elke keer een zin samenstelt van de vorm naam + werkwoord + “een” + naamwoord. Als de gebruiker op ‘enter’ drukt komt er een nieuwe zin. while True: print(kies(naam), kies(werkwoord), 'een', kies(naamwoord), end='.\n') input() Python [P2] Project: Gekke zinnen versie 12/03/2015 1/1 Een voorbeeld van het programma Dit is een voorbeeld van enkele zinnetjes die het programma kan maken: Sybille speelt met een horloge. Mauro speelt met een sleutelgat. Matthias rijdt met een bloem. Victor kuist een ruimteschip. Xander speelt met een eend. Bjarne rijdt met een huis. Martijn kiest een leeuw. Jelle koopt een vliegtuig. Bjarne schildert een dinosaurus. Xander speelt met een beer. Matthias speelt met een eend. Martijn schildert een sleutelgat. Michiel schildert een wasmand. Mauro zoekt een eend. Victor maakt een sleutel. Jelle speelt met een printer. Iljo kiest een elektrische tandenborstel. Het programma blijft oneindig lopen. Om het af te breken druk je op Ctrl+C. De volledige code # Gekke zinnen naam = ['Bjarne', 'Jelle', 'Juul', 'Martijn', 'Matthias', 'Mauro', 'Michiel', 'Sybille', 'Victor', 'Wim', 'Xander'] werkwoord = ['koopt', 'rijdt met', 'zoekt', 'drinkt', 'speelt met', 'eet', 'kuist', 'schildert', 'maakt', 'kiest'] naamwoord = ['leeuw', 'fiets', 'vliegtuig', 'wasmand', 'horloge', 'schilderpalet', 'bloem', 'bal', 'eend', 'beer', 'dinosaurus', 'huis', 'ruimteschip', 'printer', 'machine', 'elektrische tandenborstel', 'sleutelgat', 'sleutel'] from random import randint def kies(woorden): aantal_woorden = len(woorden) woordnummer = randint(0, aantal_woorden - 1) gekozen_woord = woorden[woordnummer] return gekozen_woord while True: print(kies(naam), kies(werkwoord), 'een', kies(naamwoord), end='.\n') input() Python [P2] Project: Gekke zinnen versie 12/03/2015 2/2 [P3] Project: Tekenmachine Vereiste voorkennis: fiches [7] [10] [11] [12] [13] [14] (dit programma is sterk geïnspireerd door het boek “Programmeren voor kinderen” van Carol Vorderman) Opdracht In leerfiche [21] leer je meer over turtle, de Python-bibliotheek die gebruikt kan worden om eenvoudige lijntekeningen te maken. Wat je met turtle kan doen is vergelijkbaar met de tekenfuncties die ook in Scratch beschikbaar zijn. Om in turtle te tekenen gebruik je eenvoudige functies. Met het onderstaande programma bv. kan je een huis tekenen: from turtle import * reset() left(90) forward(100) right(45) forward(70) right(90) forward(70) right(45) forward(100) right(90) forward(100) Voor dit project gaan we een tekenprogramma maken, waarbij we tijdens de uitvoering van het programma vereenvoudigde commando’s kunnen geven om iets te tekenen: F100: om 100 stappen voorwaarts (forward) te gaan B100: om 100 stappen achterwaarts (backward) te gaan R90: om 90 graden naar rechts te draaien L90: om 90 graden naar links te draaien U: om de pen omhoog (up) te doen en dus te stoppen met tekenen D: om de pen omlaag te doen (down) en dus te beginnen met tekenen N: om een nieuwe tekening te beginnen De commando’s moeten individueel kunnen gegegeven worden, maar moeten ook na elkaar kunnen gegeven worden, gescheiden met streepjes. Bijvoorbeeld: N-L90-F100-R45-F70-R45-F100-R90-F100 om het huis te tekenen dat we hierboven al aangegeven hebben. Als de gebruiker “END” tikt moet het programma stoppen. Python [P3] Project: Tekenmachine versie 12/03/2015 1/5 Wat hebben we nodig? Om dit tekenprogramma te maken hebben we de volgende onderdelen nodig: - De turtle-bibliotheek om te tekenen Een dialoogvenster om de commando’s door de gebruiker te laten intypen Een functie om een ingegegeven tekst op te splitsen in verschillende commando’s Een functie om de commando’s te vertalen naar turtle-tekeninstructies Aan de slag Volg mee via P3_Tekenmachine.py We beginnen het programma met het importeren van de turtle-bibliotheek: from turtle import * Als eerste functie gaan we een turtle_controller() maken. Die functie moet een commando (bv. F70) omzetten naar een instructie in turtle (bv. forward(70)). De twee delen van het commando splitsen we op voorhand op en geven we door als argumenten aan de functie (“doe” en “waarde”). We geven dus bv. als commando in de code turtle_controller('F', 70) op. def turtle_controller(doe, waarde): doe = doe.upper() if doe == 'F': forward(waarde) elif doe == 'B': backward(waarde) elif doe == 'R': right(waarde) elif doe == 'L': left(waarde) elif doe == 'U': penup() elif doe == 'D': pendown() elif doe == 'N': reset() else: print('Commando niet herkend') De bovenstaande functie begint met doe = doe.upper(). Daarmee zorgen we dat we zeker met hoofdletters aan het werken zijn – ‘f’ wordt dan omgezet naar ‘F’. Nu wordt er gekeken naar de letter zelf. Bij F, R, L, U, D en N zetten we het commando om naar een bijhorend commando in turtle. Als de letter iets anders blijkt te zijn, printen we op de Python shell dat we het commando niet herkend hebben. De volgende functie die we nodig hebben is een functie om een commandoreeks (een “programma”) van een gebruiker (bv. F100-R90-B50) om te zetten naar afzonderlijke turtle_controller() commando’s. Python [P3] Project: Tekenmachine versie 12/03/2015 2/5 Dat wordt de functie string_artist() die als enige parameter de volledige commandoregel aanvaardt. def string_artist(programma): cmd_list = programma.split('-') for commando in cmd_list: cmd_len = len(commando) if cmd_len == 0: continue cmd_type = commando[0] num = 0 if cmd_len > 1: num_string = commando[1:] num = int(num_string) print(commando + ':', cmd_type, num) turtle_controller(cmd_type, num) De functie string_artist() begint met het opsplitsen van de opgegeven string in verschillende strings. Daarvoor gebruiken we de stringfunctie .split('-'), waarmee we Python vertellen dat een streepje de splitsing aanduidt tussen de onderdeeltjes. Elk onderdeeltje wordt als een string in een lijst gestoken. Die lijst bewaren we in de variabele cmd_list. Als ons commando “N-L90-F100” is, zal cmd_list een lijst zijn met drie elementen: “N”, “L90” en “F100”. In de for-lus van de functie doorlopen we de commandolijst, en bekijken we bij elk commando hoe lang het is. - - Als de lengte 0 is, waren er bv. 2 streepjes na elkaar (--) en hebben we geen commando om te verwerken. Ga direct door naar de volgende lus. Als de lengte meer dan 0 is, slaan we de eerste letter (de letter met volgnummer 0) op in de variabele cmd_type. We gaan er om te beginnen van uit dat het getal dat bij het commando hoort “0” is. Bijvoorbeeld bij het “N” commando is er geen getal nodig, en daar blijft het getal dus 0. Dat getal slaan we op in num. Vervolgens kijken we of het commando langer dan 1 karakter is. Zo ja, dan beschouwen we alles vanaf positie 1 tot het einde als een getal, en dan plaatsen we dat getal in de variabele num. Nu geven we in de Python-shell de vertaling van het programma, met een print() commando. Als laatste stap geven we de variabelen cmd_type en num door als parameters aan de functie turtle_controller(). Nu wordt er effectief getekend. Tot zover de functies. En dan nu het hoofdprogramma zelf. We laten het hoofdprogramma beginnen met het bepalen van een uitleg. We steken deze in de variabele instructies. Python [P3] Project: Tekenmachine versie 12/03/2015 3/5 instructies = '''Geef een programma in voor de schildpad: bv. F100-R45-U-F100-L45-D-F100-R90-B50 N = Nieuwe tekening U = Pen omhoog D = Pen neer F100 = 100 voorwaarts B50 = 50 achterwaarts R90 = rechterdraai 90 graden L45 = linkerdraai 45 graden END = stoppen''' Nu willen we deze instructies laten zien in een dialoogvenster. Om zo’n dialoogvenster te kunnen maken moeten we een speciale variabele bijhouden waarin wordt gespecifieerd in welk venster turtle aan het tekenen is. Dat doen we via de turtle-functie getscreen(). scherm = getscreen() Nu kunnen we op de variabele scherm een aantal methodes gebruiken om bv. een dialoogvenster te laten verschijnen. Via de verbonden functie .textinput() kunnen we een venstertje maken met een bepaalde titel en een bepaalde tekst, en onderaan een kadertje waar de gebruiker zaken kan intypen. We laten dit kadertje verschijnen in een herhalingslus, die we blijven herhalen tot de gebruiker niets intypt of expliciet “END” intypt. while True: t_program = scherm.textinput('Tekenmachine', instructies) print(t_program) if t_program == None or t_program.upper() == 'END': break string_artist(t_program) De bovenstaande lus laat dus achtereenvolgens volgende zaken gebeuren: - Toon een input-venstertje met de naam “Tekenmachine” en toon de instructie-tekst. Print wat de gebruiker ingetypt heeft naar de Python Shell. Als de gebruiker op Cancel heeft geklikt of hij heeft ‘END’ ingetypt: breek de lus af Anders: roep onze functie string_artist() op en geef de invoer van de gebruiker door als parameter. Een voorbeeld van het programma Om het programma te testen kan je een aantal commando’s uitproberen. Wil je een leuk voorbeeld van een lange commandolijn, dan kan je onderstaande tekst gebruiken. Er zit ook een voorbeeld tussen van een nietherkend commando (‘K’). N-F100-L90-F200-L90-F50-R60-F30-L120-F30-R60-F40-R60-F30-L120-F30-R60-F50-L90F200-L90-F100-L90-U-F150-L90-F20-D-F30-L90-F30-L90-F30-L90-F30-R90-U-F40-D-F30R90-K-F30-R90-F30-R90-F30-L180-U-F60-R90-D-F40-L120-F40-L120-F40 Python [P3] Project: Tekenmachine versie 12/03/2015 4/5 Als resultaat verschijnt er een apart tekenvenster. Op de achtergrond worden allerlei zaken weggeschreven naar de Python Shell. De volledige code # Tekenmachine from turtle import * def turtle_controller(doe, waarde): doe = doe.upper() if doe == 'F': forward(waarde) elif doe == 'B': backward(waarde) elif doe == 'R': right(waarde) elif doe == 'L': left(waarde) elif doe == 'U': penup() elif doe == 'D': pendown() elif doe == 'N': reset() else: print('Commando niet herkend') Python [P3] Project: Tekenmachine versie 12/03/2015 5/5 def string_artist(programma): cmd_list = programma.split('-') for commando in cmd_list: cmd_len = len(commando) if cmd_len == 0: continue cmd_type = commando[0] num = 0 if cmd_len > 1: num_string = commando[1:] num = int(num_string) print(commando + ':', cmd_type, num) turtle_controller(cmd_type, num) # Voorbeeldcommando: ''' N-L90-F100-R45-F70-R90-F70-R45-F100-R90-F100 ''' instructies = '''Geef een programma in voor de schildpad: bv. F100-R45-U-F100-L45-D-F100-R90-B50 N = Nieuwe tekening U = Pen omhoog D = Pen neer F100 = 100 voorwaarts B50 = 50 achterwaarts R90 = rechterdraai 90 graden L45 = linkerdraai 45 graden END = stoppen''' scherm = getscreen() while True: t_program = scherm.textinput('Tekenmachine', instructies) print(t_program) if t_program == None or t_program.upper() == 'END': break string_artist(t_program) # Goed voorbeeld: ''' N-F100-L90-F200-L90-F50-R60-F30-L120-F30-R60-F40-R60-F30-L120-F30-R60-F50-L90F200-L90-F100-L90-U-F150-L90-F20-D-F30-L90-F30-L90-F30-L90-F30-R90-U-F40-D-F30R90-K-F30-R90-F30-R90-F30-L180-U-F60-R90-D-F40-L120-F40-L120-F40 ''' Python [P3] Project: Tekenmachine versie 12/03/2015 6/6 [P4] Project: De P-taal Vereiste voorkennis: fiches [7] [10] [11] [13] [14] Opdracht Ken je de P-taal? De P-taal is een grappige taal waarbij er na elke klinker in een woord een 'p' gezet wordt, waarna de klinker nog eens herhaald wordt. Dus bijvoorbeeld het zinnetje “Ik wil een boterham met choco” wordt dan “Ipik wipil eepeen bopoteperhapam mepet chopocopo.” Sommige mensen kunnen deze taal heel snel spreken. Dat klinkt heel gek. We gaan een programma maken waarbij de gebruiker een zinnetje mag intypen, dat dan wordt omgezet naar de p-taal. Als extraatje mag de gebruiker daarna een nieuwe letter kiezen, (bv. de k) en dan zetten we het zinnetje nog even om naar de nieuwe taal (in dit geval de k-taal). Wat hebben we nodig? - Een functie om een tekst om te zetten naar de p-taal. De letter ‘p’ moet kunnen vervangen worden door een andere letter. In de functie moeten we er rekening mee houden dat klinkers soms elkaar opvolgen. Het woord “baas” mag niét worden omgezet naar “bapaapas”, maar moet “baapaas” worden. Aan de slag Volg mee via P4_PTaal.py Het meeste werk in dit programma zal zitten in de functie die de omzetting moet doen. We definiëren die als een functie met twee parameters: de eerste (verplichte) parameter is de om te zetten tekst, de tweede (optionele) parameter is de letter waarmee we gaan werken. Standaard is dit de ‘p’. def zetOm(tekst, taalLetter='p'): We beginnen onze functie met het bepalen van de lengte van de opgegeven tekst. We maken ook twee lege string-variabelen, waarin we onze nieuwe tekst gaan bijhouden die we maken, en waarin we een opeenvolging van klinkers gaan bijhouden. lengte = len(tekst) nieuweTekst = '' klinkersAchtereen = '' Nu gaan we in een lus over onze tekst lopen. We zouden dat op een aantal manieren kunnen doen, maar het eenvoudigst in dit geval is om met een for-lus te werken die begint bij 0, die elke keer 1 verhoogt en die eindigt bij de lengte van het woord. Bij elke keer dat de lus loopt, kunnen we een lettertje bestuderen. Python [P4] Project: De P-taal versie 12/03/2015 1/3 Wat gaan we precies doen in de lus? We gaan bekijken wat voor letter we hebben op de huidige positie, en dan gaan we bekijken of dat een klinker is of niet. Als het een klinker is slaan we hem eventjes op (want misschien komen er meerdere klinkers achtereen). Als het geen klinker is, mogen we klinkers beginnen herhalen. We schrijven onze taalletter (p) weg in de string, en we herhalen ons groepje klinkers dat we bijeen gespaard hebben. Vervolgens maken we dat groepje klinkers weer leeg. for positie in range(lengte): letter = tekst[positie] if letter in ('a', 'e', 'i', 'o', 'u', 'y'): klinkersAchtereen += letter else: if klinkersAchtereen != '': nieuweTekst += taalLetter + klinkersAchtereen klinkersAchtereen = '' nieuweTekst += letter Helemaal op het einde, nàdat onze for-lus afgelopen is, moeten we nog even kijken of er toevallig nog klinkers in ons klinkerspaarpotje zitten. Als dat het geval is, dan eindigde ons woord met een klinker, en dan moeten we nog even de taalletter herhalen, gevolgd door de klinker. Bv. CoderDojo eindigt op “o”, dus er moet nog even “po” achter komen, zodat we “CopodeperDopjopo” krijgen. if klinkersAchtereen != '': nieuweTekst += taalLetter + klinkersAchtereen Tenslotte beëindigen we onze functie door onze nieuwe tekst terug te geven. return nieuweTekst Daarmee hebben we het moeilijkste achter de rug! Tijd voor het hoofdprogramma, waarin er niets verrassends staat: we begroeten onze lezer, en we vragen een woord. Daarna gebruiken we onze functie om de tekst om te zetten. print('De P-taal') print('---------\n') print(inleiding + '\n') ingegevenTekst = input('Welk woordje of welk zinnetje wil je omzetten? ') print('In de P-taal wordt dat:', zetOm(ingegevenTekst)) Tenslotte vragen we nog aan onze gebruikers om een nieuwe letter in te geven. Daarbij controleren we wel even of hij wel degelijk 1 letter (niet meer, niet minder) heeft ingegeven. nieuweLetter = input('Als je wil kan je nog een andere letter kiezen ook. \ Om bijvoorbeeld de N-taal te maken.\nKies een letter >>> ') if len(nieuweLetter) == 1: print(zetOm(ingegevenTekst, nieuweLetter)) else: print('Je hebt geen geldige letter ingegeven.') That’s it! Python [P4] Project: De P-taal versie 12/03/2015 2/3 Een voorbeeld van het programma De P-taal --------Ken je de P-taal? De P-taal is een grappige taal waarbij er na elke klinker in een woord een 'p' gezet wordt, waarna de klinker nog eens herhaald wordt. Sommige mensen kunnen deze taal heel snel spreken. Dat klinkt heel gek. Als je hieronder woordjes intypt, worden ze omgezet in de P-taal. Welk woordje of welk zinnetje wil je omzetten? De kat krabt de krollen van de trap. In de P-taal wordt dat: Depe kapat krapabt depe kropollepen vapan depe trapap. Als je wil kan je nog een andere letter kiezen ook. Om bijvoorbeeld de N-taal te maken. Kies een letter >>> t Dete katat kratabt dete krotolleten vatan dete tratap. De volledige code # De p-taal inleiding = '''Ken je de P-taal? De P-taal is een grappige taal waarbij er na elke klinker in een woord een 'p' gezet wordt, waarna de klinker nog eens herhaald wordt. Sommige mensen kunnen deze taal heel snel spreken. Dat klinkt heel gek. Als je hieronder woordjes intypt, worden ze omgezet in de P-taal.''' def zetOm(tekst, taalLetter='p'): # Deze functie zet een tekst om naar de p-taal # Via de optionele parameter 'taalLetter' kunnen we ook naar een andere taal gaan lengte = len(tekst) # We bekijken eerst hoe lang onze tekst is nieuweTekst = '' # We voorzien een lege string om te vullen met de p-tekst klinkersAchtereen = '' # Een hulpvariabele om onze klinkers tijdelijk in bij te houden for positie in range(lengte): letter = tekst[positie] if letter in ('a', 'e', 'i', 'o', 'u', 'y'): # Als de letter die we bekijken een klinker is klinkersAchtereen += letter # Voeg de letter toe aan onze hulpstring else: # Het is een medeklinker if klinkersAchtereen != '': # We hebben 1 of meerdere klinkers zitten in de hulpstring nieuweTekst += taalLetter + klinkersAchtereen # Voeg een 'p' toe, gevolgd door de klinkers die we opgeslagen hadden klinkersAchtereen = '' # Maak deze hulpstring nu weer leeg nieuweTekst += letter # Voeg nu de letter die we bekijken toe aan onze nieuwe tekst # We zijn klaar met de tekst af te lopen # Voor we de nieuwe tekst teruggeven moeten we nog even controleren of er niets meer in # onze hulpstring zit. Zo ja, dan moeten we nog een 'p' en de hulpstring toevoegen if klinkersAchtereen != '': nieuweTekst += taalLetter + klinkersAchtereen return nieuweTekst Python [P4] Project: De P-taal versie 12/03/2015 3/3 # HOOFDPROGRAMMA # print('De P-taal') print('---------\n') print(inleiding + '\n') ingegevenTekst = input('Welk woordje of welk zinnetje wil je omzetten? ') print('In de P-taal wordt dat:', zetOm(ingegevenTekst)) nieuweLetter = input('Als je wil kan je nog een andere letter kiezen ook. \ Om bijvoorbeeld de N-taal te maken.\nKies een letter >>> ') if len(nieuweLetter) == 1: # Het is 1 karakter print(zetOm(ingegevenTekst, nieuweLetter)) else: print('Je hebt geen geldige letter ingegeven.') Python [P4] Project: De P-taal versie 12/03/2015 4/4 [P5] Project: Bellenschieter Vereiste voorkennis: fiches [7] [8] [9] [11] [12] [13] [14] [18] (dit programma is sterk geïnspireerd door het boek “Programmeren voor kinderen” van Carol Vorderman) Opdracht We gaan een grafisch spelletje maken, waarbij we met een duikboot onder water varen en luchtbellen moeten kapot prikken. We werken niet met sprites – dat zijn tekeningen die we importeren en gebruiken – maar we gaan alles zelf tekenen, met de grafische bibliotheek tkinter. We werken dus met vereenvoudigde voorstellingen voor bv. de duikboot. Om het spel te spelen is er een beperkte tijd. Na één minuut is het spel afgelopen en krijg je een score. Wie meer dan 1000 punten scoort binnen de minuut krijgt bonustijd en mag ietsje langer spelen. Wat hebben we nodig? - De grafische bibliotheek tkinter, om onze vormen te tekenen. Een apart venster waarin we onze grafische elementen laten verschijnen. Een aftelklok. We gebruiken daarvoor de bibliotheek time. De besturing van het spel loopt via de pijltjestoetsen. We moeten deze toetsaanslagen dus opvangen in ons programma. Op het einde geven we een score. Die moeten we dus bijhouden in de loop van het programma. We werken met vereenvoudigde vormen. Dit wordt onze duikboot: Aan de slag We beginnen met het importeren van de nodige bibliotheken: import import import import tkinter random time math We gebruiken - tkinter: om te tekenen random: om willekeurige getallen te genereren time: om met tijdsfuncties te werken math: om geavanceerde wiskundige bewerkingen te gebruiken. De hoogte en breedte van ons venster gaan we in constanten gaan definiëren. Door deze constanten aan te passen kunnen we dus gemakkelijk de grootte van ons spel aanpassen. Python [P5] Project: Bellenschieter versie 12/03/2015 1/10 HOOGTE = 500 BREEDTE = 800 Nu gaan we het venster in kwestie gaan maken. Dat doen we met de Tk() functie uit de tkinter-bibliotheek. venster = tkinter.Tk() We geven een titel aan het venster: venster.title('Bellenschieter') En nu gebruiken we een speciale klasse Canvas() uit de tkinter-bibliotheek om het eigenlijke venster te tekenen. We geven hierbij de breedte en hoogte op, en geven via de bg parameter ook al direct op dat we het venster donkerblauw willen opvullen (darkblue). c = tkinter.Canvas(venster, width=BREEDTE, height=HOOGTE, bg='darkblue') c.pack() Nu gaan we onze duikboot tekenen. De duikboot bestaat uit een driehoek (een veelhoek of polygoon met drie zijden) en een cirkel (een ovaal waarvan de hoogte gelijk is aan de breedte. De functies create_polygon() en create_oval() kunnen binnen een Canvas() object gebruikt worden om zo’n vormen te tekenen. Om uit te leggen hoe er binnen een venster met coördinaten wordt gewerkt, bekijken we even een tekening. Je ziet een horizontale as (x-as) en een verticale as (y-as). De linkerbovenhoek van ons tekenvenster is het nulpunt. De negatieve waarden vallen bij ons dus “buiten beeld”. Om een cirkel te tekenen met als middelpunt (x=3, y=2) en straal 2 moeten we het commando create_oval(2, 1, 4, 3) gebruiken. Daarmee geven we de coördinaten op van de uiterste hoekpunten Python [P5] Project: Bellenschieter versie 12/03/2015 2/10 van een rechthoek (het groene punt is (2, 1), het oranje punt is (4, 3). Binnen die rechthoek wordt dan een ovaal getekend – in ons geval een perfecte cirkel. Bij create_polygon() werken we nog wat anders: daar geven we de coördinaten op van de drie verschillende hoeken van onze driehoek. Onderstaande commando’s tekenen dus een driehoek en een ovaal. ship_id = c.create_polygon(5, 5, 5, 25, 30, 15, fill='red') ship_id2 = c.create_oval(0, 0, 30, 30, outline='red') We houden in een constante ook bij hoe groot onze duikboot is. De cirkel heeft een straal van 15. Die waarde houden we bij in de constante SHIP_R. SHIP_R = 15 Nu gaan we onze duikboot in het midden van ons venster positioneren. Om het midden te bepalen delen we zowel de breedte als de hoogte door 2. Met de Canvas()-functie .move() verplaatsen we zowel de cirkel als de driehoek naar de nieuwe coördinaten. MID_X = BREEDTE / 2 MID_Y = HOOGTE / 2 c.move(ship_id, MID_X, MID_Y) c.move(ship_id2, MID_X, MID_Y) Onze basis-opzet is er: een blauwe zee met een rode duikboot in het midden. Nu moeten we zorgen dat we de duikboot kunnen besturen. Daarvoor maken we een constante waarin we de snelheid (speed) van het schip bijhouden: SHIP_SPD = 10 en vervolgens definiëren we een functie om het schip te bewegen. De functie zal als parameter een “event” meekrijgen. Die event zal vanuit ons hoofdprogramma komen en zal “Up”, “Down”, “Left” of “Right” zijn – afhankelijk van welke pijltjestoets we ingedrukt hebben. De functie werkt vrij simpel: bij elke pijltjesbeweging verplaatsen we ons schip met dezelfde .move()-functie die we daarnet al gebruikt hebben. Bij move() geven we drie parameters op: - wat we willen bewegen (de driehoek of de cirkel) hoeveel we naar links en rechts willen bewegen – dit getal blijft 0 als we op en neer gaan, zal een negatief getal zijn als we naar links gaan en zal een positief getal zijn als we naar rechts gaan hoeveel we naar boven en onder willen bewegen – dit getal blijft 0 als we naar links en rechts gaan, zal een negatief getal zijn als we naar boven gaan en zal een positief getal zijn als we naar beneden gaan. Python [P5] Project: Bellenschieter versie 12/03/2015 3/10 De grootte van het getal wordt bepaald door onze snelheid (SHIP_SPD). def beweeg_schip(event): if event.keysym == 'Up': c.move(ship_id, 0, -SHIP_SPD) c.move(ship_id2, 0, -SHIP_SPD) elif event.keysym == 'Down': c.move(ship_id, 0, SHIP_SPD) c.move(ship_id2, 0, SHIP_SPD) elif event.keysym == 'Left': c.move(ship_id, -SHIP_SPD, 0) c.move(ship_id2, -SHIP_SPD, 0) elif event.keysym == 'Right': c.move(ship_id, SHIP_SPD, 0) c.move(ship_id2, SHIP_SPD, 0) De manier om deze functie te activeren bij het indrukken van een toets is via de functie .bind_all() die we op ons Canvas()-object kunnen toepassen. c.bind_all('<Key>', beweeg_schip) We geven dus niet alleen de pijltjestoetsen door. Ook als je bv. spatiebalk drukt zal dit doorgegeven worden naar de functie beweeg_schip(). Maar we doen binnen die functie beweeg_schip() enkel iets met de pijltjestoetsen – de rest wordt gewoon genegeerd. Ons spel is niet volledig zonder luchtbellen. Da’s dus de volgende stap. We gaan véél bellen hebben, dus we gaan de bellen bijhouden in een aantal lijsten. bub_id bub_r bub_speed = list() = list() = list() In bub_id houden we de identificatienummers van de bellen bij, in bub_r houden we de straal (de grootte) van de bellen bij en in bub_speed de snelheid waarmee ze bewegen. Er zijn veel verschillende bellen, van verschillende groottes. De grootte en de snelheid wordt willekeurig bepaald, maar we bepalen wel grenzen. We houden ook bij hoeveel afstand er tussen 2 bellen moet blijven: MIN_BUB_R MAX_BUB_R MAX_BUB_SPD TUSSEN = = = = 10 30 10 100 Tijd voor een functie om de bellen effectief te maken. De bellen gaan van rechts naar links vliegen, dus we gaan ze laten “ontstaan” nét buiten het scherm, aan de rechterkant. De x-coördinaat – die bepaalt hoever iets naar rechts ligt wordt gelijk gesteld met de breedte van het venster + de tussenafstand tussen 2 bellen. De bel zal dus volledig buiten beeld zijn. Verder bepalen we een willekeurige hoogtepositie van de bel (y) en een willekeurige straal (r) , binnen de grenzen die we bepaald hadden. Python [P5] Project: Bellenschieter versie 12/03/2015 4/10 def maak_bel(): x = BREEDTE + TUSSEN y = random.randint(0, HOOGTE) r = random.randint(MIN_BUB_R, MAX_BUB_R) id1 = c.create_oval(x - r, y - r, x + r, y + r, outline='white') bub_id.append(id1) bub_r.append(r) bub_speed.append(random.randint(1, MAX_BUB_SPD)) De bovenstaande functie sluit af met het effectieve tekenen van de bel (.create_oval()). De referentie naar de bel wordt eerst in een tijdelijke variabele id1 gestoken en vervolgens bij ons lijstje bub_id gehangen. Ook de straal hangen we bij de bub_r-lijst. In de bub_speed-lijst tenslotte steken we een willekeurig bepaalde snelheid voor de bel. In ons hoofdprogramma gaan we in een oneindige lus moeten de bellen laten bewegen. Daarvoor maken we een functie beweeg_bellen() waarin we telkens de hele lijst met bellen aflopen, en de positie van de bellen aanpassen via .move(). def beweeg_bellen(): for i in range(0, len(bub_id)): c.move(bub_id[i], -bub_speed[i], 0) We zullen ook een functie nodig hebben die de coördinaten kan opvragen van een opgegeven bel. Bekijk terug de tekening met de coördinaten op de x- en y-as enkele bladzijden terug. Om de coördinaten van het middelpunt van de cirkel te vinden moeten we de x- en y-coördinaten van de hoekpunten van de omliggende rechthoek optellen bij elkaar en delen door 2: def get_coords(id_num): pos = c.coords(id_num) x = (pos[0] + pos[2])/2 y = (pos[1] + pos[3])/2 return x, y We zijn er bijna met onze functies. We hebben nog een functie nodig om de bellen te doen verdwijnen. Bellen gaan verdwijnen zodra we ze aanraken met onze duikboot, of als we het programma opschonen (zie ietsje verder). Om een bel te laten verdwijnen, verwijderen we hem uit al onze lijstjes, en verwijderen we hem vanuit ons venster met het delete() commando. def verdwijn_bel(i): del bub_r[i] del bub_speed[i] c.delete(bub_id[i]) del bub_id[i] Om te zorgen dat ons programma niet vreselijk traag wordt, gaan we de bellen die niet meer in beeld zijn, ook laten “verdwijnen”. Dat doen we door bij elke stap te kijken of er bellen zijn waarvan de x-coördinaat negatief is. Die zijn dus buiten beeld. Python [P5] Project: Bellenschieter versie 12/03/2015 5/10 def bellen_opschonen(): for i in range(len(bub_id)-1, -1, -1): x, y = get_coords(bub_id[i]) if x < -TUSSEN: verdwijn_bel(i) We hebben nog een functie nodig om de afstand tussen 2 punten te berekenen. Hiervoor wordt de stelling van Pythagoras gebruikt. Je hoeft die niet te kennen en te snappen – gebruik gewoon onderstaande code: def afstand(id1, id2): x1, y1 = get_coords(id1) x2, y2 = get_coords(id2) return math.sqrt((x2 - x1)**2 + (y2 - y1)**2) En dan nog de lààtste bellen-functie die we nodig hebben: één om een bel te laten verdwijnen als we er met onze duikboot tegen zitten. Om dat te controleren gaan we de afstand tussen het middelpunt van elke bel en het middelpunt van onze duikboot berekenen. Als er ergens een bel is waarvan de afstand kleiner is dan de som van de straal van de bel en de straal van de duikboot, dan hebben we een botsing. In dat geval verdwijnt de bel, en krijgen we er punten voor. def botsing(): punten = 0 for bub in range(len(bub_id)-1, -1, -1): if afstand(ship_id2, bub_id[bub]) < (SHIP_R + bub_r[bub]): punten += (bub_r[bub] + bub_speed[bub]) verdwijn_bel(bub) return punten Nu hebben we nog een functie nodig om de tijd en de score te tonen. Dat doen we met de Canvas()-functie .create_text(). # Score en tijd tonen c.create_text(50, 30, text='TIJD', fill='white') c.create_text(150, 30, text='SCORE', fill='white') time_text = c.create_text(50, 50, fill='white') score_text = c.create_text(150, 50, fill='white') def toon_score(score): c.itemconfig(score_text, text=str(score)) def toon_tijd(tijd_over): c.itemconfig(time_text, text=str(tijd_over)) Python [P5] Project: Bellenschieter versie 12/03/2015 6/10 Daarmee hebben we alle functies. Tijd om het hoofdprogramma te laten lopen. Daarin bepalen we eerst nog een paar variabelen: - BUB_CHANCE: bepaalt hoe vaak er een bel komt. Hoe hoger dit getal, hoe minder snel de bellen zullen komen. score: om onze score bij te houden TIJDSLIMIET: na hoeveel seconden het spel afgelopen is BONUS_SCORE: hoeveel we moeten halen om bonustijd te krijgen bonus: om onze bonusscore bij te houden eindtijd: om te bepalen wanneer het spel eindigt. Dat is de huidige tijd plus de tijdslimiet. # MAIN # BUB_CHANCE = 10 score = 0 TIJDSLIMIET = 30 BONUS_SCORE = 1000 bonus = 0 eindtijd = time.time() + TIJDSLIMIET Nu laten we een herhalingslus lopen. Die blijft lopen zolang de huidige tijd kleiner is dan de bepaalde eindtijd. In de herhalingslus - maken we een bel aan bewegen we alle bellen verwijderen we de bellen die niet meer in beeld zijn updaten we de score bekijken we of de bonusscore bereikt is updaten we de getoonde score en de getoonde tijd verversen we de inhoud van het venster wachten we 0,01 seconde voor we aan de volgende lus beginnen. while time.time() < eindtijd: if random.randint(1, BUB_CHANCE) == 1: maak_bel() beweeg_bellen() bellen_opschonen() score += botsing() if (int(score / BONUS_SCORE)) > bonus: bonus += 1 eindtijd += TIJDSLIMIET toon_score(score) toon_tijd(int(eindtijd - time.time())) venster.update() time.sleep(0.01) Als we uit de lus komen, is het spel afgelopen. We voorzien nog wat tekst voor de “Game over”. Python [P5] Project: Bellenschieter versie 12/03/2015 7/10 # Game over c.create_text(MID_X, MID_Y, text='GAME OVER', fill='white', font=('Helvetica', 30)) c.create_text(MID_X, MID_Y+30, text='Score: ' + str(score), fill='white') c.create_text(MID_X, MID_Y+45, text='Bonustijd: ' + str(bonus*TIJDSLIMIET), fill='white') Een voorbeeld van het programma Zo ziet het programma er uit in volle actie: Python [P5] Project: Bellenschieter versie 12/03/2015 8/10 De volledige code # Duikbootspel import tkinter import random import time import math HOOGTE = 500 BREEDTE = 800 # Maak het venster venster = tkinter.Tk() venster.title('Bellenschieter') c = tkinter.Canvas(venster, width=BREEDTE, height=HOOGTE, bg='darkblue') c.pack() # Maak de duikboot ship_id = c.create_polygon(5, 5, 5, 25, 30, 15, fill='red') ship_id2 = c.create_oval(0, 0, 30, 30, outline='red') SHIP_R = 15 MID_X = BREEDTE / 2 MID_Y = HOOGTE / 2 c.move(ship_id, MID_X, MID_Y) c.move(ship_id2, MID_X, MID_Y) # De duikboot besturen SHIP_SPD = 10 def beweeg_schip(event): if event.keysym == 'Up': c.move(ship_id, 0, -SHIP_SPD) c.move(ship_id2, 0, -SHIP_SPD) elif event.keysym == 'Down': c.move(ship_id, 0, SHIP_SPD) c.move(ship_id2, 0, SHIP_SPD) elif event.keysym == 'Left': c.move(ship_id, -SHIP_SPD, 0) c.move(ship_id2, -SHIP_SPD, 0) elif event.keysym == 'Right': c.move(ship_id, SHIP_SPD, 0) c.move(ship_id2, SHIP_SPD, 0) c.bind_all('<Key>', beweeg_schip) # Bellen definieren bub_id = list() bub_r = list() bub_speed = list() MIN_BUB_R = 10 MAX_BUB_R = 30 MAX_BUB_SPD = 10 TUSSEN = 100 def maak_bel(): x = BREEDTE + TUSSEN y = random.randint(0, HOOGTE) r = random.randint(MIN_BUB_R, MAX_BUB_R) id1 = c.create_oval(x - r, y - r, x + r, y + r, outline='white') bub_id.append(id1) bub_r.append(r) bub_speed.append(random.randint(1, MAX_BUB_SPD)) Python [P5] Project: Bellenschieter versie 12/03/2015 9/10 # Laat de bellen bewegen def beweeg_bellen(): for i in range(0, len(bub_id)): c.move(bub_id[i], -bub_speed[i], 0) def get_coords(id_num): pos = c.coords(id_num) x = (pos[0] + pos[2])/2 y = (pos[1] + pos[3])/2 return x, y # Bellen doen verdwijnen def verdwijn_bel(i): del bub_r[i] del bub_speed[i] c.delete(bub_id[i]) del bub_id[i] def bellen_opschonen(): for i in range(len(bub_id)-1, -1, -1): x, y = get_coords(bub_id[i]) if x < -TUSSEN: verdwijn_bel(i) # Afstand tussen twee punten def afstand(id1, id2): x1, y1 = get_coords(id1) x2, y2 = get_coords(id2) return math.sqrt((x2 - x1)**2 + (y2 - y1)**2) # Laat de bellen knallen def botsing(): punten = 0 for bub in range(len(bub_id)-1, -1, -1): if afstand(ship_id2, bub_id[bub]) < (SHIP_R + bub_r[bub]): punten += (bub_r[bub] + bub_speed[bub]) verdwijn_bel(bub) return punten # Score en tijd tonen c.create_text(50, 30, text='TIJD', fill='white') c.create_text(150, 30, text='SCORE', fill='white') time_text = c.create_text(50, 50, fill='white') score_text = c.create_text(150, 50, fill='white') def toon_score(score): c.itemconfig(score_text, text=str(score)) def toon_tijd(tijd_over): c.itemconfig(time_text, text=str(tijd_over)) Python [P5] Project: Bellenschieter versie 12/03/2015 10/10 # MAIN # BUB_CHANCE = 10 score = 0 TIJDSLIMIET = 30 BONUS_SCORE = 1000 bonus = 0 eindtijd = time.time() + TIJDSLIMIET while time.time() < eindtijd: if random.randint(1, BUB_CHANCE) == 1: maak_bel() beweeg_bellen() bellen_opschonen() score += botsing() if (int(score / BONUS_SCORE)) > bonus: bonus += 1 eindtijd += TIJDSLIMIET toon_score(score) toon_tijd(int(eindtijd - time.time())) venster.update() time.sleep(0.01) # Game over c.create_text(MID_X, MID_Y, text='GAME OVER', fill='white', font=('Helvetica', 30)) c.create_text(MID_X, MID_Y+30, text='Score: ' + str(score), fill='white') c.create_text(MID_X, MID_Y+45, text='Bonustijd: ' + str(bonus*TIJDSLIMIET), fill='white') Python [P5] Project: Bellenschieter versie 12/03/2015 11/11 [P6] Project: Kleurbollen Opdracht Wat hebben we nodig? Aan de slag Een voorbeeld van het programma De volledige code [P7] Project: Botsbal Opdracht Wat hebben we nodig? Aan de slag Een voorbeeld van het programma De volledige code [P8] Project: Stokjesman Opdracht Wat hebben we nodig? Aan de slag Een voorbeeld van het programma De volledige code Python [P6] Project: Kleurbollen versie 12/03/2015 1/1