ID.nl logo
Zo kun je programmeren in Python - deel 8
© Reshift Digital
Zekerheid & gemak

Zo kun je programmeren in Python - deel 8

Tot nu toe leerde je heel wat mogelijkheden van de programmeertaal Python. Misschien ben je buiten onze lessen zelf al aan de slag gegaan met je kennis. Super, want programmeren leer je door het veel te doen. Maar een goed programma is ook gedocumenteerd en goed getest. Dat leer je in onze achtste les.

Hier vind je les 1 van de Python-cursus.

Verkeerde gewoontes leer je niet snel af, daarom dat we nu even een stapje terugdoen en nadenken over wat ‘goede code’ is. Na deze les kun je code produceren die niet alleen goed gedocumenteerd en goed getest is, maar weet je ook hoe je informatie over Python-modules opzoekt met de helpfunctie.

Code documenteren met commentaar

Tot nu toe schreven we onze code zonder enige vorm van documentatie. Als je met anderen samenwerkt aan een programma, is het belangrijk dat je die documenteert, zodat je anderen duidelijk maakt wat je met je code bedoelt. Maar ook als je helemaal alleen programmeert, is documentatie geen overbodige luxe. Zo begrijp je je eigen code nog als je er over een jaar opnieuw naar kijkt.

De eerste manier om je code te documenteren is met commentaar. Alles na het #-teken (hekje) tot het einde van de regel (behalve als het hekje ín een string voorkomt) is commentaar en wordt door Python genegeerd. Op die manier kun je een uitleg voor jezelf of anderen schrijven. Als je bijvoorbeeld in de functie is_palindroom van deel 6 in de war raakt met die indexen, schrijf er dan gerust wat commentaar bij:

if letters[0] != letters[-1]: # Als de eerste en de laatste letter verschillen

Het getuigt van goede stijl om twee spaties tussen je code en het erna volgende commentaarteken te houden en één spatie tussen het commentaarteken en je commentaar. Overigens kun je ook commentaar op een nieuwe losstaande regel beginnen, dan spreken we van een commentaarregel:

# Als de eerste en de laatste letter verschillen

if letters[0] != letters[-1]:

Het is de gewoonte om een commentaarregel te zetten op de regel vóór de regel waarover hij gaat.

Code uitcommentariëren

Het commentaarteken (#) wordt ook weleens gebruikt om code die je aan het testen bent maar die niet blijkt te werken tijdelijk ‘uit te commentariëren’ ofwel uit te zetten. Door een commentaarteken voor de code te zetten, wordt de code door Python genegeerd, maar kun je hem erna wel eenvoudig weer inschakelen door het commentaarteken weg te halen. Op deze manier gebruik je het commentaarteken dus niet voor documentatie, maar eigenlijk als hulpmiddel bij het debuggen.

Code documenteren met docstrings

Commentaar gebruik je om te documenteren waarom je iets doet en hoe je het doet, maar voor gebruikers van je code is vooral belangrijk wat die doet. Om dat te documenteren, gebruik je docstrings: in het begin van elke module, elke klasse en elke functie of methode geef je met een string tussen drie dubbele aanhalingstekens aan wat het stuk code doet.

Zo zouden we onze klassen uit de vorige les als volgt kunnen documenteren:

"""Klassen om met tweedimensionale, driedimensionale en hogerdimensionale punten te werken."""

import math

class Point:
"""Stelt een punt voor in een willekeurig aantal dimensies."""

def __init__(self, *coordinates):
"""Initialiseer het punt met de opgegeven coördinaten."""
self.coordinates = list(coordinates)

def __repr__(self):
"""Geef een leesbare voorstelling van het punt terug."""
return 'Point(' + ', '.join(str(co) for co in self.coordinates) + ')'

def displacement(self, other_point):
"""Geef het verschil terug tussen dit punt en een ander punt.

De overeenkomstige coördinaten worden van elkaar afgetrokken.

Voorbeeld: het verschil tussen Point(1, 4, 2) en Point(3, 4, 1) is gelijk aan Point(2, 0, -1).
"""
return Point(*[a-b for a, b in zip(other_point.coordinates, self.coordinates)])

def distance(self, other_point):
"""Geef de Euclidische afstand terug tussen dit punt en een ander punt."""
relative_position = self.displacement(other_point)
return math.sqrt(sum(i**2 for i in relative_position.coordinates))
class Point2D(Point):
"""Stelt een tweedimensionaal punt voor."""

def __init__(self, x=0, y=0):
"""Initialiseer het punt met de opgegeven x- en y-coördinaten."""
Point.__init__(self, x, y)
self.x = x
self.y = y
def get_x(self):

"""De x-coördinaat van het punt."""
return self.coordinates[0]

def set_x(self, x):
self.coordinates[0] = x

x = property(get_x, set_x)

def get_y(self):
"""De y-coördinaat van het punt."""
return self.coordinates[1]

def set_y(self, y):
self.coordinates[1] = y

y = property(get_y, set_y)

Je ziet hier dat documentatie niet lang hoeft te zijn. De docstrings bij de module, de klassen en bij de meeste methodes zijn maar één regel lang.

De moeilijkste methode om te begrijpen is displacement en daarom is het zinvol om daar wat meer uitleg bij te geven. Bij een docstring van meer dan één regel raden we aan om na de eerste regel een lege regel te houden, en om de drie dubbele aanhalingstekens op het einde op een nieuwe regel te zetten. Dat geeft wat meer overzicht.

Merk op: bij onze eigenschappen x en y van de klasse Point2D documenteren we alleen de methode die de waarde van de eigenschap opvraagt. Zo toont de ingebouwde helpfunctie van Python (die we op het einde van deze les bespreken) deze documentatie bij de eigenschap.

Interactieve voorbeelden in docstrings

We hebben in de docstring van de methode displacement al een voorbeeld van het gebruik van de methode gegeven als documentatie. Maar dat bleef nogal informeel. We kunnen die documentatie ook in de vorm van echte Python-code doen die je in een interactieve terminalsessie zou kunnen invoeren. Zo kan de gebruiker die de documentatie leest, onmiddellijk de voorbeelden kopiëren uit de documentatie en plakken in de Python-interpreter om ze uit te proberen. Dat zou voor de methode displacement er dan als volgt uitzien:

def displacement(self, other_point):"""Geef het verschil terug tussen dit punt en een ander punt.

De overeenkomstige coördinaten worden van elkaar afgetrokken.

>>> Point(1, 4, 2).displacement(Point(3, 4, 1))Point(2, 0, -1)"""return Point(*[a-b for a, b in zip(other_point.coordinates, self.coordinates)])

Je ziet hier dat je de code na de >>> exact in een Python-terminalsessie zou kunnen invoeren en dan ook het resultaat zou krijgen dat hier staat. In feite hebben we wat hier staat gewoon eerst in de terminal van Thonny ingevoerd en dan samen met de uitvoer gekopieerd en hier in de docstring geplakt.

Code testen met doctest

Stel dat je nu ooit de code van de methode displacement aanpast omdat je denkt een verbetering te zien, maar er een fout in maakt, waardoor het resultaat verkeerd is. Dan kun je dat testen door de voorbeeldcode in je docstring uit te voeren in een Python-terminalsessie. Voer je de code uit en komt het resultaat niet overeen met de uitvoer in de docstring, dan klopt je code niet meer.

Maar zouden we die test niet automatisch kunnen doen? Jazeker! Python kent daarvoor de module doctest, die automatisch alle docstrings in een module kan testen op interactieve voorbeelden. Dat voer je als volgt uit in een Linux- of macOS-terminal of de Windows Opdrachtprompt:

python3 -m doctest -v point.py

Hierbij is point.py de naam van de module met je code erin. Je krijgt dan als uitvoer de tests die doctest in je docstrings ziet en het resultaat. Als je het alleen wilt zien als een test een fout vindt, haal dan de optie -v weg. Stel dat je bijvoorbeeld per ongeluk de * vergeten bent in de methode displacement om de lijst naar een willekeurig aantal argumenten voor de klasse Point om te zetten, dan zal doctest die fout opmerken met de volgende melding:

**********************************************************************

File "point.py", line 21, in point.Point.displacement

Failed example:

Point(1, 4, 2).displacement(Point(3, 4, 1))

Expected:

Point(2, 0, -1)

Got:

Point([2, 0, -1])

**********************************************************************

1 items had failures:

1 of

***Test Failed*** 1 failures.

Een goede manier van programmeren is dan ook dat je je code zoveel mogelijk documenteert met docstrings en daarin ook interactieve voorbeelden opneemt, die je na elke wijziging van je code automatisch test met doctest om je ervan te verzekeren dat je geen fouten hebt geïntroduceerd.

De helpfunctie gebruiken

Als je code is gedocumenteerd, hoef je niet je codebestand in Thonny te openen om de documentatie te bekijken. Je kunt dit in een interactieve Python-sessie, bijvoorbeeld in Thonny, maar ook in een Python-sessie in een Linux- of macOS-terminal of de Windows Opdrachtprompt. Het enige wat je hoeft te doen, is de functie help op te roepen met de naam van de module, klasse, functie of methode waarvoor je de documentatie wilt zien. Bijvoorbeeld in Thonny:

>>> help(Point.displacement)

Help on function displacement in module __main__:

displacement(self, other_point)

Geef het verschil terug tussen dit punt en een ander punt.

De overeenkomstige coördinaten worden van elkaar afgetrokken.

>>> Point(1, 4, 2).displacement(Point(3, 4, 1))

Point(2, 0, -1)

Overigens zijn alle standaardmodules van Python uitgebreid gedocumenteerd met docstrings. Daardoor kun je van alle modules, klassen, functies en methodes heel eenvoudig documentatie opvragen in je Python-terminalsessie. Let er wel op dat je een module eerst dient te importeren voordat je er documentatie van kunt opvragen met help.

Samenvatting

In deze les ging het minder over het programmeren zelf, maar over het documenteren en testen van je Python-programma’s en het uitzoeken van meer informatie over de standaard Python-modules of je eigen modules. Hoe complexer je programma’s zijn, hoe belangrijker dit soort zaken rond je code zijn. Maak er daarom een gewoonte van om documentatie en tests niet als een nabeschouwing te zien, maar al tijdens de ontwikkeling van je programma in je code te integreren. In de volgende les maken we het nog complexer: dan gaan we extra modules installeren die niet in Python ingebouwd zijn.

Opdracht 1

Voer de helpfunctie eens uit op je klasse Point2D. Wat zou er nog beter kunnen aan de getoonde documentatie?

Uitwerking opdracht 1

*>>> from point import Point2D

help(Point2D)* De helpfunctie van onze klasse toont niet alleen de eigenschappen x en y bij de Data descriptors, maar toont ook de methodes get_x, set_x, get_y en set_y. Dat is wat te veel van het goede. Die methodes hoeven niet getoond te worden. Daar doen we in de volgende opdracht iets aan.

Opdracht 2

We hebben een eigenschap zoals x in de klasse Point2D tot nu toe geconstrueerd met methodes get_x en set_x en een opdracht als x = property(get_x, set_x) om deze methodes samen als eigenschap te gebruiken. Maar je kunt een eigenschap ook met een decorator definiëren en dan worden die methodes niet in de helpuitvoer getoond. Zoek zelf met de ingebouwde helpfunctie van Python op hoe je dat doet.

Uitwerking opdracht 2

Met help(property) krijg je uitleg over de opdracht property. Je leert er zelfs dat het geen opdracht maar een klasse is. Het in de helpuitvoer getoonde voorbeeld kun je bijna rechtstreeks toepassen op onze klasse Point2D. Dan kom je tot de volgende code voor x: *@propertydef x(self):"""De x-coördinaat van het punt."""return self.coordinates[0]@x.setter**def x(self, x):*self.coordinates[0] = x Doe hetzelfde voor y. Voer de helpfunctie opnieuw uit op je klasse en verifieer dat je alleen nog maar hulp over de eigenschappen krijgt en niet meer over de methodes die de eigenschappen opbouwen.

Cheatsheet

Commentaar: een regel die begint met # en dient als uitleg bij een stukje code. Debuggen: fouten (bugs) in je code opsporen en verhelpen. Docstring: een string tussen drie dubbele aanhalingstekens die een module, klasse, functie of methode documenteert. Uitcommentariëren: een regel code uitschakelen door er een commentaarteken voor te zetten.

▼ Volgende artikel
Review Philips Café Aromis 8000-serie - Horecakoffie gewoon bij je thuis
© Philips
Huis

Review Philips Café Aromis 8000-serie - Horecakoffie gewoon bij je thuis

Thuis koffie van restaurantkwaliteit? De Philips Café Aromis 8000-serie belooft het. In deze review lees je of deze volautomaat de hype waarmaakt. Van perfect melkschuim tot minimaal onderhoud: ontdek waarom dit apparaat je lokale barista overbodig maakt, zelfs met gewone supermarktbonen!

Fantastisch
Conclusie

Dit is meer dan een keukenapparaat; het is een stukje levensgeluk. Je hoeft niet meer te kiezen tussen gemak en smaak. De Philips Café Aromis 8000 bewijst dat je dat perfecte koffiemomentje gewoon thuis kunt creëren. Zonder barista-cursus, zonder gedoe, maar mét die gelukzalige stilte na de eerste slok.

Plus- en minpunten
  • Barista-melkschuim zonder slangetjes
  • Haalt goud uit supermarktbonen
  • Stil in gebruik
  • Einde aan discussies dankzij gebruikersprofielen
  • Foolproof bediening: iedereen kan nu topkoffie zetten
  • Vakje voor gemalen koffie is wat knullig
  • Geen actieve kopjeswarmer
  • Plastic lekbak voelt goedkoop aan

Je kent het vast: je zit in je favoriete koffietentje, neemt een eerste slok van de cappuccino die je hebt besteld en valt even stil. De temperatuur, het mondgevoel, die volle smaak… alles lijkt te kloppen. En dan denk je aan de koffie thuis. Die is prima, of in elk geval best oké. Maar daar blijft het dan ook bij.

Dat dacht ik tenminste. Tot ik de Philips Café Aromis 8000-serie op mijn aanrecht installeerde en mijn keuken stante pede in een soort hippe koffiebar veranderde. De installatie van deze fraaie machine behelst niet meer dan een stekker in het stopcontact, water in het reservoir en een dosis verse koffiebonen bovenin. That’s it. Daarna kan het feest beginnen.

Hoewel de term 'restaurantkwaliteit' vaak niet meer dan een loze marketingkreet is, maakt dit apparaat dat woord opeens bizar concreet. Dat zit 'm in heel basale dingen: de koffie is direct op de juiste temperatuur (niet dat lauwe net-niet) en de smaak is vol en romig, zonder die nare bittere nasmaak. Dit apparaat lijkt bovendien precies te snappen wat jij wil; zonder dat je zelf als een bezetene aan de knoppen hoeft te draaien, staat er binnen de kortste keren een meer dan fatsoenlijke kop koffie voor je neus. Wat een topding!

©Philips

Bonen vs cups: fight!

Voor wie nog twijfelt om de overstap te maken van cups naar bonen: doe het. Het verschil is niet subtiel, het is een aardverschuiving. Waar capsules vaak toch een beetje vlak smaken, proef je hier ineens nuances die je eerder miste. Het apparaat oogt misschien intimiderend professioneel, maar de bediening is uiteindelijk net zo simpel als je gewend bent van je good old Nespresso.

Duurdoenerij niet nodig

Erg prettig is het feit dat de machine enorm vergevingsgezind is. Hippe koffiesnobs vertellen je doorgaans dat je zonder exclusieve bonen van 30 euro per kilo nergens bent. Onzin, blijkt nu. Zelfs met een zak supermarktbonen en een pak volle melk (lang houdbaar werkt het best!) tovert dit ding een resultaat tevoorschijn waar je u tegen zegt. Hij weet echt het maximale uit elke boon te persen. Luxe zonder dat je boodschappenlijstje ingewikkeld of overdreven duur wordt, ik hou ervan.

En dan de melk. Vaak is dat thuis niet meer dan een zielig laagje luchtbelletjes dat na tien seconden als sneeuw voor de zon verdwijnt. Hier niet. Dit schuim is stevig, rijk en blijft dapper overeind staan. M'n ochtendcappuccino heb ik dan ook spontaan heilig verklaard, maar de echte verrassing is wat mij betreft de optie 'Melange'. Die is gloeiend heet, heeft de ideale verhouding tussen melk en koffie (puristen verklaren me voor gek) en maakt me elke keer weer instant gelukkig. Ik was aanvankelijk wat sceptisch over dit soort voorgeprogrammeerde recepten, maar deze verhouding is zo perfect afgestemd dat het elke keer weer aanvoelt als een echte traktatie.

©Philips

'Wat willen jullie drinken?'

Bezoek over de vloer? Kom maar door met de bestellingen! Vroeger hoopte ik stiekem op de keuze voor zwart (want: geen gedoe met melk), nu draai ik mijn hand niet meer om voor een latte of espresso macchiato. Sterker nog, ik nodig mensen nu vol enthousiasme uit om een kopje koffie te komen doen, en de reacties zijn elke keer unaniem: "Wauw, lekkere koffie!" 

Het mooie is dat je specifieke voorkeuren van je bezoek niet elke keer opnieuw hoeft in te voeren. Dankzij de gebruikersprofielen heeft iedereen in huis zijn eigen 'knop'. De een wil de latte met extra melk, de ander wil 'm juist sterker: dat kun je allemaal opslaan. En de machine verrast ook in de breedte. Waar ik zelf inmiddels min of meer verslaafd ben aan de Red Eye (een pittige boost voor de korte nachten), scoor ik bij mijn dochter punten met de 'Babychino'-functie: alleen warm melkschuim. Lekker voor het slapen gaan. 

Voor de liefhebbers zitten er trouwens nog allerlei cold brew-opties in het assortiment. Niet helemaal mijn ding – koffie kan me niet heet genoeg – maar fijn dat het kan als de smaak (of het bezoek) daarom vraagt.

©Eelko Rol

Geen schoonmaak-nachtmerries

Dan het onderhoud. We kennen de horrorverhalen van schimmelende slangetjes in volautomaten en hopeloos verkalkte zetgroepen. De Café Aromis 8000 is wat dat betreft een verademing. Water bijvullen, bakje met koffiepucks legen en (belangrijk!) de melkhouder gewoon even omspoelen onder de kraan (schijnt zelfs in de vaatwasser te kunnen). Geen ingewikkeld gedoe; de machine spoelt zichzelf krachtig door bij het opstarten en afsluiten. Het ding staat er, hij werkt en zeurt verder niet om aandacht. Had ik al gezegd dat dit een topding is?

O, en er is een app. Is die noodzakelijk? Neuh. Is het lekker? Ja! Via de app kun je de machine alvast aan het werk zetten terwijl je zelf nog even je mail checkt in bed. Je weet: technologie is op zijn best als het je luiheid faciliteert, en dat heeft Philips hier goed begrepen.

©Philips

Conclusie? Dit is meer dan een keukenapparaat; het is een stukje levensgeluk. Je hoeft niet meer te kiezen tussen gemak (dag Senseo!) en smaak. De Philips Café Aromis 8000 bewijst dat je dat perfecte koffiemomentje gewoon thuis kunt creëren. Zonder barista-cursus, zonder gedoe, maar mét die gelukzalige stilte na de eerste slok.

Enige minpuntje is wellicht de prijs, want die is met 999 euro best fors. Maar reken maar uit: een cappuccino kost tegenwoordig al snel 4 euro, dus met 250 gloeiend hete geluksmomentjes thuis heb je deze machine er al uit. Dat moet je jezelf gewoon gunnen.

▼ Volgende artikel
Voormalige Assassin's Creed-baas klaagt Ubisoft aan
Huis

Voormalige Assassin's Creed-baas klaagt Ubisoft aan

Marc-Alexis Côté, die voorheen de Assassin's Creed-gamefranchise bij Ubisoft overzag, heeft dat bedrijf nu aangeklaagd.

Nieuw op ID: het complete plaatje

Misschien valt het je op dat er vanaf nu ook berichten over games, films en series op onze site verschijnen. Dat is een bewuste stap. Wij geloven dat technologie niet stopt bij hardware; het gaat uiteindelijk om wat je ermee beleeft. Daarom combineren we onze expertise in tech nu met het laatste nieuws over entertainment. Dat doen we met de gezichten die mensen kennen van Power Unlimited, dé experts op het gebied van gaming en streaming. Zo helpen we je niet alleen aan de beste tv, smartphone of laptop, maar vertellen we je ook direct wat je erop moet kijken of spelen. Je vindt hier dus voortaan de ideale mix van hardware én content.

Afgelopen oktober werd aangekondigd dat Côté vertrokken was bij het bedrijf. Dat gebeurde rond dezelfde tijd als dat Ubisoft de Assassin's Creed-franchise onderbracht onder Vantage Studios, een nieuwe dochteronderneming die het samen met Tencent heeft opgericht. Côté heeft decennialang aan de Assassin's Creed-franchise gewerkt en stond de laatste jaren aan het hoofd van de populaire spellenreeks.

Côté zou toen Assassin's Creed naar Vantage Studios ging een aanbod van Ubisoft hebben gekregen om een andere leidende positie binnen het bedrijf aan te nemen. Côté liet kort daarna publiekelijk weten dat deze positie niet vergelijkbaar was met zijn eerdere werk.

De aanklacht

Nu klaagt Côté Ubisoft dus aan, zo meldt CBC Radio Canada. Volgens hem zou hij de rol van 'Head of Production' aangeboden hebben gekregen binnen Ubisoft nadat Assassin's Creed binnen Vantage Studios werd ondergebracht, gevolgd door een mogelijke positie als 'Creative House'.

Volgens Côté zou hij daardoor leiderschap krijgen over "tweederangs" Ubisoft-franchises. Aangezien hij daarvoor de Assassin's Creed-franchise overzag, voelde dit voor hem als een wezenlijke stap terug.

Côté nam naar eigen zeggen twee weken vrij om over deze situatie te reflecteren. Aan het einde van die periode zou Ubisoft hebben geëist dat hij een besluit moest maken en besloot Côté dat dit een onacceptabele situatie was, en een "ontslag in vermomming". Hij eiste dan ook ontslagvergoeding, waarna hij te horen kreeg dat hij niet meer op werk hoefde te komen en Ubisoft aankondigde dat hij was vertrokken.

Volgens Côté heeft Ubisoft geclaimd dat hij vrijwillig is vertrokken, zodat men geen ontslagvergoeding hoefde te betalen. Côté eist nu twee jaar aan loon als ontslagvergoeding en 75.000 dollar aan schadevergoeding vanwege machtsmisbruik en schade aan zijn reputatie. In totaal komt dat neer op meer dan 1,3 miljoen dollar. Ook wil hij dat het concurrentiebeding komt te vervallen.

Vantage Studios en Assassin's Creed

Ubisoft richtte vorig jaar samen met het Chinese Tencent de dochteronderneming Vantage Studios op. Daar zijn de drie belangrijkste Ubisoft-franchise in ondergebracht, namelijk Assassin's Creed, Far Cry en Rainbow Six. Ook de ontwikkelteams die aan deze reeksen werken maken nu onderdeel uit van Vantage Studios.

De Assassin's Creed-franchise is al jarenlang een van de belangrijkste gamereeksen van de Franse uitgever Ubisoft. In de spellen gebruiken spelers parkour, stealth en gevechten om diverse exotische locaties uit de geschiedenis te verkennen. Het meest recente deel is het vorig jaar uitgekomen Assassin's Creed Shadows.