Leren Programmeren in Python Deel 1

Wat in dit deel aan bod komt:


Voorwoord

Aan de hand van een reeks voorbeelden leggen we wat uit over programmeren in Python.

Hyperlinks waarvan de achtergrond verkleurt bij aanwijzen, leiden naar een externe webplek.
Voor de liefhebbers: Python 2.2.2 was het uitgangspunt; bijgewerkt voor Python 2.3.3.

Waar het om gaat:

Waar je iets van moet leren:

Als gereedschap kun je gebruiken:

Mogelijke Python IDEs:

Hulp bij kiezen en installeren van een Python IDE zullen we hier niet bieden. Het gebruik van zo'n IDE spreekt meestal voor zich en komt summier aan de orde.

Alternatieve Python inleidingen

In het Engels zijn er ook heel andere inleidingen tot programmeren in Python. Zie bijvoorbeeld de "officiële" Python Tutorial (Nederlandse vertaling: Python Tutorial; niet meer beschikbaar) of kies iets uit de Beginners Guide. Als je nog niets van programmeren weet is Learning to Program van Alan Gauld aan te bevelen. Als je spelletjes (maken) leuk vindt, kun je terecht bij Pygame.


Automat(iser)en

Alvorens zelf te gaan programmeren is het goed wat te weten van automaten. Denk aan een koffie-automaat of een mechanisch polshorloge.

Een automaat

Het polshorloge

Een computer is een programmeerbare automaat. De computer gedraagt zich als de automaat die beschreven is in een programma. Het programma is eenvoudig te vervangen. Daarom zullen we doen alsof

De belangrijkste onderdelen van een computer zijn:

De interne toestand van de nagespeelde automaat wordt in het geheugen opgeslagen. De processor doet de berekeningsstappen van de nagespeelde automaat in samenwerking met het geheugen en de I/O-eenheid.

Verderop vertellen we meer over programmeertalen. Nu volstaat het om te weten dat een programmeertaal een notatie is om een automaat te beschrijven.


Levensloop van een programma

We volgen de levensloop (Eng.: life cycle) van een klein programma aan de hand van een eenvoudig voorbeeld. We doorlopen de volgende fasen:

Dit is leesvoer. Daarna komen wat oefeningen om zelf te doen.

Probleemstelling

De probleemstelling zet het probleem uiteen in termen van de wereld waarin het zich afspeelt. In ons voorbeeld:

Hoe kun je een gegeven bedrag gepast betalen met zo min mogelijk euromunten?

Zo kun je 96 eurocent gepast betalen met 5 euromunten:

één halve euro( 1 x 50 eurocent )
twee kwintjes( 2 x 20 eurocent )
één stuiver( 1 x  5 eurocent )
één cent( 1 x  1 eurocent )

Met minder munten lukt het niet.

Specificatie voor een programma

De specificatie legt vast waaraan een programma moet voldoen om als "oplossing" van het probleem te kunnen fungeren.

De belangrijkste vragen die een specificatie dient te beantwoorden zijn:

Het is vaak ook nuttig voorbeeld-dialogen te geven. In ons voorbeeld kiezen we voor de volgende specificatie:

Invoer:
Bedrag in eurocenten, tussen 0 en 500
Uitvoer:
Tabel met het aantal keer dat iedere munt gebruikt is om het ingevoerde bedrag met zo min mogelijk euromunten gepast te betalen
Beperkingen:
Onbeperkt beschikbare euromunten met de volgende waarden (in eurocenten):
1,   2,   5,   10,   20,   50,   100,   200
Ongebruikte munten worden niet in de tabel vermeld.
Voorbeeld dialoog (invoer is geel, uitvoer is blauw):
96
1 x 50
2 x 20
1 x 5
1 x 1

Ontwerp van een programma

Het ontwerp legt in abstracte (wiskundige) termen uit hoe het probleem opgelost kan worden en waarom het een oplossing is.

Bij kleine programma's komt dit neer op een beschrijving van

Hier is een mogelijk ontwerp voor ons voorbeeld:

Variabelen:
Gehele getallen bedrag (invoer en nog te passen restbedrag), munt (om muntsoorten te doorlopen) en aantal (om te tellen hoe vaak munt gebruikt is).
Stappen:
  1. Lees bedrag in

  2. Laat munt de waarden van de euromunten dalend doorlopen

    1. Bepaal voor elke munt het maximale aantal dat gebruikt kan worden om het resterende bedrag gepast te betalen en verlaag het bedrag met elke gebruikte munt

    2. Schrijf aantal x munt, mits aantal > 0

Dat dit ontwerp inderdaad aan de voorgaande specificatie voldoet, d.w.z. een minimale gepaste betaling bij het ingevoerde bedrag levert, zullen we hier niet beargumenteren. Waarschijnlijk is dit de manier waarop de meeste eurogebruikers het doen.

Productie van een Python programma

In de productie-fase wordt het ontwerp gecodeerd in een programmeertaal die de computer kan verwerken. Het product noemen we (programma)code. Het produceren van code wordt ook wel coderen, implementeren of realiseren genoemd.

Hieronder staat de code van een Python programma bij ons voorgaande ontwerp. We leggen verderop meer uit over de notatie en de werking. Je kan het programma ook ophalen: gepast0.py, maar wacht daar nog even mee. Lees het eerst een keer door en vergelijk het met het voorgaande ontwerp:

# Een bedrag gepast betalen met zo min mogelijk euromunten

bedrag = input ( 'Geef bedrag tussen 0 en 500 eurocent: ' )

for munt in 200, 100, 50, 20, 10, 5, 2, 1 :
    aantal = 0

    while bedrag >= munt :
        aantal = aantal + 1
        bedrag = bedrag - munt

    if aantal > 0 :
        print aantal, 'x', munt

Controle

In iedere fase moet je controleren of die goed verloopt en goed afloopt. Bij dit kleine programma beperken we ons tot het controleren van de code. Deze controle bestaat uit

Dat uitproberen wordt ook testen genoemd. Op grond van de specificatie en het ontwerp kunnen we een aantal testgevallen (Eng.: test cases) bedenken en die vermelden in een testplan:

Testplan voor gepast betalen
Nr. Invoer bedrag Verwachte uitvoer (tabel) Toelichting
1  0 (geen) Kleinste bedrag volgens specificatie
2  1 1 x 1 Kleinste betaling met één munt
3  3 1 x 2
1 x 1
Kleinste betaling met twee verschillende munten
4  4 2 x 2 Kleinste betaling met tweemaal dezelfde munt
5200 1 x 200 Kleinste betaling met éénmaal de grootste munt
6388 1 x 200
1 x 100
1 x 50
1 x 20
1 x 10
1 x 5
1 x 2
1 x 1
Kleinste betaling met éénmaal elke munt
7500 2 x 200
1 x 100
Grootste bedrag volgens specificatie

Behalve geschikte invoer, dient ook de bijbehorende verwachte uitvoer vermeld te worden, alsmede een reden voor de keuze. We zullen later wel zien dat bovenstaande gevallen nog niet genoeg zijn voor een echt serieuze controle!

Als bij de controle eventuele defecten in het product ontdekt worden, dan is het zaak deze defecten te elimineren. (Dit behandelen we verder in Deel 2.)

Gebruik en onderhoud

Als je ervan overtuigd bent dat het product geen defecten meer bevat, dan kan het in gebruik genomen worden.

Bij de oefeningen hieronder mag je dat zelf doen met ons voorbeeld-programma.

Een programma slijt niet, ook niet door intensief gebruik. Toch is er bij programma's behoefte aan onderhoud:

Onderhoud aan een programma bestaat uit het doorvoeren van aanpassingen om tegemoet te komen aan veranderingen in omgeving en wensen. Hiervoor worden alle fasen nogmaals doorlopen. Dit doen we verderop.

Als een programma niet meer aan te passen is, dan wordt het afgedankt. Daar hoor je meestal niets over.


Oefeningen

Nu is het tijd om zelf wat te gaan proberen.

  1. Haal het voorgaande Python programma gepast0.py op.

  2. Open (Eng.: open) het programma met je favoriete Python IDE.

  3. Laat het programma uitvoeren (Eng.: run) voor het gegeven voorbeeld van 96 eurocent. Als om het invoerbedrag wordt gevraagd, tik dan 96 in gevolgd door de RETURN-toets en controleer de uitvoer.
    N.B. Hoe invoer moet worden aangeboden en hoe uitvoer wordt gepresenteerd hangt af van de Python IDE die je gebruikt.

  4. Probeer nu ook alle testgevallen en controleer telkens de uitvoer.
    N.B. Het programma moet elke keer opnieuw gestart worden.

  5. Probeer enkele zelfgekozen, toegestane bedragen, d.w.z. gehele getallen tussen 0 en 500.

  6. Het is ook mogelijk om een bedrag in te voeren als formule. Probeer eens de invoer  4*20 + 3*5 + 1  .

  7. Probeer een negatief bedrag (-1) en ook een niet-geheel bedrag (96.5). Wat valt je op aan de uitvoer?

  8. Probeer nu een heel groot bedrag, zeg één miljard, in formulevorm kan dit geschreven worden als  10 ** 9  . Je moet wel even geduld hebben! Later zullen we het programma versnellen. (Zie je ook al hoe dat zou kunnen?)

  9. Als je een fout maakt in de invoer, dan volgt er een foutmelding van het Python systeem. Schrik daar niet van. Probeer maar eens het volgende:

    InvoerFoutmelding
    96abc SyntaxError: Unexpected EOF while parsing ...
    abc NameError: name 'abc' is not defined ...
    'abc' TypeError: unsupported operand type(s) for -: 'str' and 'int' ...

    N.B. Hoe de foutmeldingen precies gepresenteerd worden hangt af van de Python IDE die je gebruikt.


Programmeertalen

Bij het bestuderen van een (programmeer)"taal" is het nuttig om drie aspecten te onderscheiden:

Denk aan verkeerslichten als "taal" om berichten naar bestuurders over te brengen. Er zijn allerlei soorten, veelal met rode, gele en groene lichten, waarvan de verschijningsvormen afhangen van de doelgroep (auto's, voetgangers, bussen, treinen, etc.). Ze brengen betekenissen over als Stop, Pas op en Ga. In de praktijk blijken ze vaak anders gebruikt te worden dan in de wet is vastgelegd.

Python syntax

De syntactische bouwstenen van Python programmateksten vallen in zeven categorieën:

CategorieVoorbeeld
Commentaar # Een bedrag gepast betalen met ...
Wit regelovergang,  spatie,  tab
Namen bedrag   input   munt   aantal
Sleutelwoorden for   in   while   if   print
Letterlijke waarden 200   100   50   20   10   5   2   1   0   'x'
Operatoren >=   +   -   >
Scheiders =   (   )   ,   :

In de tabel zijn koppelingen opgenomen naar de "officiële" documentatie van de programmeertaal Python. Je hoeft dat niet allemaal te begrijpen, maar je kan er allicht iets van opsteken.

Python semantiek

Belangrijke semantische bouwstenen van Python programma's zijn:

Categorie Toelichting Voorbeeld
Naam-object bindingen Op elk moment
refereert iedere naam aan één object
bedrag --> 96
munt   --> 50
aantal -->  0
  en later   bedrag --> 46
munt   --> 50
aantal -->  1
Uitdrukkingen Worden geëvalueerd tot een object
input ( '...' )    bedrag >= munt    aantal + 1
Enkelvoudige opdrachten Worden uitgevoerd
bedrag = bedrag - munt    print aantal, 'x', munt
Samengestelde opdrachten Worden uitgevoerd
afhankelijk van de toestand
for munt in ... :
    ...
   while bedrag >= munt :
    ...
   if aantal > 0 :
    ...

Hier volgt een korte toelichting bij de betekenis van Python uitdrukkingen (Eng.: expressions) en opdrachten (Eng.: statements):

Uitdrukkingen (vgl. wiskundige formules): Opgebouwd uit (o.a.) namen, letterlijke waarden, operatoren (waaronder machtsverheffen, rekenkundige bewerkingen, vergelijkingen en logische bewerkingen), functie-aanroepen en haakjes
Een uitdrukking wordt in stapjes geëvalueerd tot een waarde. De volgorde hangt af van de bindingsregels voor de operatoren en de plaatsing van haakjes. Namen worden vervangen door de waarde van het eraan gebonden object. Functie-aanroepen worden vervangen door de waarde die de functie retourneert voor de opgegeven argumenten. Zo is input een ingebouwde functie om invoer te lezen: eerst wordt het argument geschreven, daarna wordt een karakterrij (Eng.: string) ingelezen en geëvalueerd.
Uitvoer schrijven: print lijst uitdrukkingen
De lijst uitdrukkingen wordt geëvalueerd en ieder element wordt als karakterrij (Eng.: string) naar het standaard uitvoerkanaal geschreven, telkens gescheiden door één spatie.
Toekenning: naam = uitdrukking
De uitdrukking wordt geëvalueerd en toegekend aan de naam. De oude binding van deze naam gaat hiermee verloren.
Opeenvolging: blok opdrachten onder elkaar
De opdrachten worden van boven naar beneden na elkaar uitgevoerd.
N.B. Deze opdrachten moet je allemaal precies even ver inspringen.
Onconditionele herhaling: for naam in lijst uitdrukkingen :  ingesprongen blok opdrachten
De lijst uitdrukkingen wordt geëvalueerd en ieder element wordt achtereenvolgens toegekend aan naam, waarna telkens het ingesprongen blok opdrachten wordt uitgevoerd.
Conditionele herhaling: while uitdrukking :  ingesprongen blok opdrachten
De uitdrukking wordt geëvalueerd en als deze geldt wordt het ingesprongen blok opdrachten uitgevoerd; dit evalueren en uitvoeren wordt net zo lang herhaald tot de uitdrukking niet geldt.
Conditionele uitvoering: if uitdrukking :  ingesprongen blok opdrachten
De uitdrukking wordt geëvalueerd en als deze geldt wordt het ingesprongen blok opdrachten eenmalig uitgevoerd.

Met behulp van deze semantische bouwstenen is alles wat programmeerbaar is ook te programmeren. We behandelen in de volgende delen nog wel meer, maar die uitbreidingen dienen alleen het programmeergemak; ze voegen geen essentiële nieuwe mogelijkheden toe.

Hieronder volgt een tabel met het waardenverloop bij uitvoering van gepast0.py met invoer 96. Een '?' staat voor een ongedefinieerde waarde. Een groene achtergrondskleur duidt op een nieuw toegekende waarde.

Invoer en Uitvoer bedrag munt aantal Conditie Toelichting
Geef bedrag ... ? ? ? ... input ( 'Geef bedrag ...' )
96 ? ? ? ingetikt door gebruiker
96 ? ? bedrag = ...
96 200 ? for munt in 200, ... :
96 200 0   aantal = 0
96 200 0 False   while bedrag >= munt :
96 200 0 False   if aantal > 0 :
96 100 0 for munt in ..., 100, ... :
etc. etc.

Python pragmatiek

Met betrekking tot goede programmeergewoontes (en die gelden niet alleen voor programmeren in Python) vermelden we:

Nette opmaak Spaties, bijv. rond namen, operatoren en =, en na komma's;
lege regels, bijv. vóór en na herhalingen met for en while;
systematisch inspringen
Helder commentaar Vermelding van programmadoel, auteur(s) en datum;
toelichting bij variabelen en stappen
Zinvolle namen Gerelateerd aan hun doel
Geschikt interface Toelichtende tekst laten schrijven bij interactief inlezen van waarden;
nette uitvoer schrijven
Systematisch controleren programmatekst vergelijken met ontwerp;
programma uitproberen met vooraf gekozen testinvoer en vooraf bekende testuitvoer

Ons eerste voorbeeld programma gepast0.py heeft een nette opmaak, bevat commentaar, gebruikt zinvolle namen en heeft een geschikt interface. Ook hebben we systematische tests gegeven. Het commentaar en interface zijn voor verbetering vatbaar. Dat zien we in het volgende deel.

Bovengenoemde goede gewoontes vergen enige inspanning vooraf en de meerwaarde is misschien niet meteen duidelijk. Maar ze zijn in de loop der jaren ontstaan, omdat gebleken is dat ze helpen bij het maken van betere programma's. In een rommelig programma maak je veel makkelijker fouten die veel lastiger te vinden zijn. Achteraf "oppoetsen" van een programma kost meer moeite dan het meteen netjes doen.

Als afschrikwekkend voorbeeld volgt hier een Python programmatekst gepast0a.py die syntactisch anders is, maar semantisch hetzelfde als het eerder gegeven voorbeeld. Het heeft minimaal wit, geen commentaar, gebruikt de kortste namen en heeft een karig interface:

a=input()
for b in 200,100,50,20,10,5,2,1:
 c=0
 while a>=b:
  c=c+1
  a=a-b
 if c>0:
  print c,b

Niet veel mensen zullen bereid zijn je te helpen met het zoeken naar fouten in zo'n programma! Vergelijk het nog maar eens met het eerste product.


Meer oefeningen

Hier volgen nog wat meer oefeningen.

  1. Ga aan de hand van eerdergenoemde testgevallen na dat het verwerpelijke programma gepast0a.py inderdaad hetzelde "doet".

  2. Pas het nettere programma gepast0.py zo aan dat onder de geschreven tabel ook het totaal aantal gebruikte munten wordt vermeld (dit is een uitbreiding van de specificatie).
    Geef bedrag tussen 0 en 500 eurocent:
    96
    1 x 50
    2 x 20
    1 x 5
    1 x 1
    Aantal munten: 5

    Introduceer hiervoor een nieuwe variabele met naam totaal en als doel het totale aantal gebruikte munten te tellen (dit is een uitbreiding van het ontwerp).

    Wijzig vervolgens de code en test het resulterende programma.

    Kopieer eerst het programma gepast0.py naar gepast0b.py. (De namen van Python programma's kunnen het beste op .py eindigen.) Open de kopie, breng de wijzigingen aan en bewaar (Eng.: save) de gewijzigde versie.

    N.B. Als je bij het wijzigen iets verkeerd doet, kun je bij het uitvoeren van het programma een foutmelding krijgen. Zo moeten opdrachten die in een blok bijelkaar horen even ver ingesprongen zijn.

  3. De methode die we gebruiken om gepast te betalen staat bekend als een gretig algoritme, omdat telkens zoveel mogelijk van de grootste nog bruikbare munt wordt ingezet. Dit algoritme werkt niet optimaal voor alle soorten munten.

    Pas in het voorgaande programma de muntwaarden aan tot die voor het oude Nederlandse geld zonder kwartje:

    5,   10,   100,   250,   500
    Het invoerbedrag dient nu een 5-voud te zijn, anders kan het natuurlijk niet gepast worden. Bedenk (nieuwe) testgevallen en probeer ze uit. Zoek ook invoer waarvoor de betaling niet klopt of niet minimaal is.

Samenvatting

In de levensloop van een programma hebben we de volgende fasen onderscheiden:

Van de programmeertaal Python hebben we met de volgende onderdelen kennisgemaakt:

Commentaar
tekst Commentaar Vanaf # wordt de tekst tot het einde van de regel genegeerd
Uitdrukkingen
naam Uitdrukking De waarde van het object waar de naam aan gebonden is
letterlijke waarde Uitdrukking De letterlijke waarde zelf
uitdrukking operator uitdrukking Uitdrukking De operator wordt toegepast op de waarden van de uitdrukkingen
uitdrukking ) Uitdrukking De waarde van de uitdrukking; doorbreekt de standaardvolgorde van evaluatie
functie ( lijst uitdrukkingen ) Uitdrukking De waarde geretourneerd door de functie aangeroepen met de lijst uitdrukkingen als argumenten
Uitvoer
print lijst uitdrukkingen Enkelvoudige opdracht De lijst uitdrukkingen wordt geëvalueerd tot karakterrij en dan geschreven; elementen worden gescheiden door één spatie; bij interactief gebruik kan print worden weggelaten
Invoer
input ( karakterrij ) Ingebouwde functie Schrijft de opgegeven karakterrij en retourneert een ingelezen, geëvalueerde karakterrij
Opeenvolging
opdracht
opdracht
Blok opdrachten Opdrachten die onder elkaar staan worden van boven naar beneden uitgevoerd
Toekenning
naam = uitdrukking Enkelvoudige opdracht De geëvalueerde uitdrukking wordt aan de naam toegekend
Conditionele Uitvoering (Selectie)
if uitdrukking :
    ingesprongen blok opdrachten
Samengestelde opdracht Als de uitdrukking geldt, wordt het ingesprongen blok opdrachten (eenmalig) uitgevoerd
Onconditionele Herhaling
for naam in lijst uitdrukkingen :
    ingesprongen blok opdrachten
Samengestelde opdracht Elementen uit de lijst uitdrukkingen worden achtereenvolgens toegekend aan naam en hierna wordt telkens het ingesprongen blok opdrachten uitgevoerd.
Conditionele Herhaling
while uitdrukking :
    ingesprongen blok opdrachten
Samengestelde opdracht Zolang de uitdrukking geldt, wordt het ingesprongen blok opdrachten (herhaaldelijk) uitgevoerd

Met een Python IDE hebben we het volgende gedaan:

Als goede programmeergewoonten zijn we tegengekomen:

[ Deel 2 ]


Copyright © 2002-2004, Tom Verhoeff
Validate HTML