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
Wat is local dimming en waarom is het belangrijk?
© ER | ID.nl
Huis

Wat is local dimming en waarom is het belangrijk?

Het gebrek aan een rijk contrast is een van de grootste ergernissen bij lcd- en ledtelevisies. Fabrikanten hebben daarom een slimme techniek bedacht die het contrast aanzienlijk verbetert: local dimming. In dit artikel leggen we uit hoe deze techniek van jouw grijze nachtlucht weer een inktzwarte sterrenhemel maakt.

Het contrast van je televisie is misschien wel de belangrijkste eigenschap voor mooi beeld. We willen dat wit verblindend wit is en zwart echt inktzwart. Bij oledtelevisies is dat makkelijk, want daar geeft elke pixel zelf licht. Maar de meeste televisies in de Nederlandse huiskamers zijn nog steeds lcd- of ledschermen (inclusief QLED). Die werken met een lamp achter het scherm, de zogeheten backlight. Local dimming is de techniek die probeert de nadelen van die achtergrondverlichting op te lossen.

Om te begrijpen waarom local dimming nodig is, moet je eerst weten hoe een standaard led-tv werkt. Simpel gezegd is het een groot paneel met pixels die zelf geen licht geven, maar alleen van kleur veranderen. Achter die pixels brandt een grote lichtbak. Als het beeld zwart moet zijn, sluiten de pixels zich om het licht tegen te houden. Helaas lukt dat nooit voor de volle honderd procent; er lekt altijd wat licht langs de randjes. Hierdoor zien donkere scènes er vaak wat flets en grijzig uit. De achtergrondverlichting staat immers vol aan, ook als het beeld donker moet zijn.

Nooit meer te veel betalen? Check Kieskeurig.nl/prijsdalers!

De lampen dimmen waar het donker is

Local dimming pakt dit probleem bij de bron aan. In plaats van één grote lichtbak die altijd aan staat, verdeelt deze techniek de achtergrondverlichting in honderden (en bij duurdere tv's soms duizenden) kleine zones. De televisie analyseert de beelden die je kijkt continu. Ziet de processor dat er linksboven in beeld een donkere schaduw is, terwijl rechtsonder een felle explosie te zien is? Dan worden de lampjes in de zone linksboven gedimd of zelfs helemaal uitgeschakeld, terwijl de lampjes rechtsonder juist fel gaan branden.

Het resultaat is direct zichtbaar. Zwart wordt weer echt zwart, simpelweg omdat er geen licht meer achter dat deel van het scherm brandt. Tegelijkertijd blijven de lichte delen van het scherm helder. Dat zorgt voor een veel groter contrast en geeft het beeld meer diepte. Vooral bij het kijken van HDR-films en -series is dat van belang. Zonder local dimming kan een led-tv eigenlijk geen goed HDR-beeld weergeven, omdat het verschil tussen licht en donker dan te klein blijft.

©ER | ID.nl

Niet alle local dimming is hetzelfde

Het klinkt als een wonderoplossing, maar de uitvoering verschilt enorm per televisie. Het grote toverwoord hierbij is het aantal zones. Hoe meer zones de tv onafhankelijk van elkaar kan aansturen, hoe preciezer het licht kan worden geregeld. Goedkopere televisies gebruiken vaak edge lit local dimming. Hierbij zitten de lampjes alleen in de rand van de tv. Dat werkt redelijk, maar is niet heel nauwkeurig. Je ziet dan soms dat een hele verticale strook van het beeld lichter wordt, terwijl er eigenlijk maar één klein object moest worden verlicht.

De betere variant heet full array local dimming. Hierbij zitten de lampjes over de hele achterkant van het scherm verspreid. De allernieuwste en beste vorm hiervan is miniLED. Daarbij zijn de lampjes zo klein geworden dat er duizenden in een scherm passen, wat de precisie van oled begint te benaderen. Als er te weinig zones zijn, kun je last krijgen van zogenaamde 'blooming'. Dat zie je bijvoorbeeld bij witte ondertiteling op een zwarte achtergrond: er ontstaat dan een soort wazige lichtwolk rondom de letters, omdat de zone groter is dan de tekst zelf.

Welke merken gebruiken local dimming?

Bijna elke grote televisiefabrikant past deze techniek inmiddels toe, maar ze doen dat voornamelijk in hun middenklasse en topmodellen. Samsung is een van de voorlopers, zeker met hun QLED- en Neo QLED-televisies, waarbij ze in de duurdere series gebruikmaken van geavanceerde miniLED-techniek voor zeer precieze dimming. Ook Sony staat bekend om een uitstekende implementatie van full array local dimming, die vaak geprezen wordt om de natuurlijke weergave zonder overdreven effecten. Philips past het eveneens toe in hun (mini)ledmodellen, vaak in combinatie met hun bekende Ambilight-systeem voor een extra contrastrijk effect.

Ga voor de full monty!

Local dimming is dus geen loze marketingkreet, maar een dankbare techniek voor iedereen die graag films of series kijkt op een led- of QLED-televisie. Het maakt het verschil tussen een flets, grijs plaatje en een beeld dat van het scherm spat met diepe zwartwaarden. Ben je in de markt voor een nieuwe tv? Vraag dan niet alleen óf er local dimming op zit, maar vooral of het gaat om full array dimming. Je ogen zullen je dankbaar zijn tijdens de volgende filmavond!

Vijf fijne televisies die full array local dimming ondersteunen

▼ Volgende artikel
Waar voor je geld: 5 robotstofzuigers voor een extra schone vloer
© ID.nl
Huis

Waar voor je geld: 5 robotstofzuigers voor een extra schone vloer

Bij ID.nl zijn we gek op producten waar je niet de hoofdprijs voor betaalt of die zijn voorzien van bijzondere eigenschappen. Met een robotstofzuiger wordt de vloer schoongehouden, terwijl je er niet bij hoeft te zijn. En stofzuigen is dan wel het minste dat ze kunnen, want ook dweilen is voor veel modellen geen proleem. We vonden vijf geavanceerde exemplaren.

Philips HomeRun 7000 Series XU7100/01

De Philips HomeRun 7000 Series XU7100/01 is ontworpen om grote ruimtes aan te kunnen. Het apparaat heeft een stofzak van 3 liter en een werktijd tot 180 minuten in de laagste stand. In tegenstelling tot veel kleinere robots is deze HomeRun uitgerust met een stille motor; de opgave van 66 dB maakt hem relatief stil.

Er zit een dweilfunctie in zodat je de robot na het stofzuigen ook direct kunt laten dweilen. Via de app kies je voor een van de modi of plan je een schoonmaakprogramma in. De robot kan zichzelf navigeren, obstakels omzeilen en keert na gebruik terug naar het laadstation. Omdat de opvangbak groot is hoef je niet vaak te legen en dankzij de Li‑ion‑accu is hij geschikt voor grotere woningen. Het apparaat is van recente datum en daarom nog volop verkrijgbaar.

Dreame L10s Pro Ultra Heat

Deze robot combineert een groot stofreservoir van 3,2 liter met een lange werktijd van ongeveer 220 minuten. Dankzij de geïntegreerde dweilfunctie verwijdert hij niet alleen stof maar kan hij ook nat reinigen. De L10s Pro Ultra Heat gebruikt een zak in het basisstation, waardoor je het reservoir minder vaak hoeft te legen.

De Dreame is voorzien van een Li‑ion‑batterij aanwezig en de robot keert automatisch terug naar het station voor opladen en legen. De sensortechnologie helpt bij het vermijden van obstakels en het nauwkeurig schoonmaken van zowel harde vloeren als tapijt. Dankzij de meegeleverde app stuur je de schoonmaak aan, stel je no‑go‑zones in of plan je een dweilrondje.

Philips HomeRun 3000 Series Aqua XU3100/01

Deze Philips‑robot is bedoeld voor wie minder vaak handmatig wil schoonmaken. Hij beschikt over een gecombineerde stofzuig‑ en dweilfunctie en kan zichzelf legen via het automatische station. Met een gebruiksduur tot 200 minuten in de laagste stand en een geluidsniveau van 66 dB kan hij urenlang zijn werk doen zonder al te veel herrie. De stofcontainer van 35 cl is kleiner dan bij de HomeRun 7000, maar door het automatische leegmechanisme is dat geen probleem.

Je bedient het apparaat via de app en kunt daar zowel een schema programmeren als zones instellen. De Aqua XU3100/01 is een model uit de recente 3000‑serie en doordat hij een mop‑pad heeft kan hij zowel droog als nat reinigen, wat handig is voor harde vloeren zoals tegels en laminaat.

iRobot Roomba Combo j9+

De Roomba Combo j9+ is een model dat je vloeren zowel kan stofzuigen als dweilen. De Combo j9 beschikt over een opvangbak van 31 cl en hij kan zelf zijn inhoud legen in het automatische basisstation dat bij de set hoort. De Li‑ion‑accu zorgt voor een lange gebruiksduur en de robot maakt een routeplanning zodat elke ruimte efficiënt wordt schoongemaakt.

Via de app kun je zones instellen waar de robot niet mag komen en het dweilelement in‑ of uitschakelen. In de basis maakt de Combo j9+ zelfstandig een kaart van je woning en keert terug naar het station wanneer de accu moet opladen of de stofcontainer vol is. De robot is bedoeld voor huishoudens die gemak belangrijk vinden en biedt naast stofzuigen ook een dweilfunctie voor hardere vloeren.

MOVA Tech P50 Ultra

De MOVA Tech P50 Ultra is een forse robotstofzuiger met een basisstation. Het apparaat heeft een stofreservoir van 30 cl en wordt geleverd met een basisstation waarin je het stof eenvoudig kunt verwijderen. De robot produceert een geluidsniveau van 74 dB, iets hoger dan de Philips‑modellen, en weegt inclusief station ruim 13 kg.

Hij kan uiteraard ook automatisch terugkeren naar het station om op te laden of te legen. In de specificaties staat dat de MOVA is voorzien van een Li‑ion‑batterij en dat hij zowel kan stofzuigen als dweilen. De meegeleverde app maakt het mogelijk om routes in te stellen en zones te blokkeren. Met een vermogen van 700 W is hij krachtig genoeg voor tapijten en harde vloeren. Het is geschikt voor mensen die een uitgebreid station met automatische functies willen.