Python Pagina

Waarom Python?

De programmeertaal Python is de laatste jaren heel populair geworden. De taal is makkelijk te leren en ziet er overzichtelijke uit. Er is een variant van Python die op microprocessors zoals de ESP8266 kan draaien.
Python is een scripttaal. Dat heeft voor- en nadelen. Talen zoals Delphi Pascal, of Visual C++ zijn geen scripttalen. Zij lezen de programma brontekst, zetten die om in code die voor de computer makkelijk uit te voeren is en voegen bibliotheken toe. Zo wordt een uitvoerbaar bestand gemaakt, dat erg snel zal werken. Omdat de hele brontekst meerdere keren kan worden doorlopen voordat deze is omgezet in machine code, kunnen nog extra optimalisaties worden doorgevoerd.
Bij scripttalen zoals Python wordt de brontekst elke keer opnieuw gelezen, geïnterpreteerd en omgezet in machinecode. Uiteraard is dat veel langzamer. Ook Python kent een aantal optimalisaties, maar uiteindelijk zal het programma toch zo'n 100 keer langzamer lopen dan een uitvoerbaar bestand. Met de huidige snelle computers is het bij verreweg de meeste programma's niet relevant hoe snel ze worden uitgevoerd.
Een programma dat jouw Python code uitvoert kun een interpreter noemen, maar het woord compiler wordt ook veel gebruikt. Als je de naam IDE gebruikt, dan bedoel je een programma dat meer doet dan alleen je Python programma uitvoeren. Zo zal een IDE vaak een editor hebben die automatisch inspringt en cijfers, gereserveerde woorden en dergelijke in andere kleuren weergeeft. Voorbeelden zijn PyCharm, IDLE, Visual Studio Code, Spyder en Thonny. Een groot nadeel van uitvoerbare bestanden is dat deze anders zijn bij verschillende types computer en besturingssystemen. Je moet dus voor elk besturingssysteem of computertype opnieuw een uitvoerbaar bestand maken en dat is niet altijd mogelijk. Bij Delphi kan dat alleen voor Windows, iOS en Android en Linux. Python werkt op al deze systemen en ook op de Raspberry Pi.
Met Python kun je erg snel een programma ontwikkelen: elke wijziging kun je meteen testen. En er is nog een voordeel: elk programma is leesbare tekst en kan dus gemakkelijk via mail of over internet verspreid worden. Bij uitvoerbare programma's wordt dat steeds moeilijker en vaak moet je er voor betalen.
Talen als Delphi Pascal en C++ gebruiken meestal ingebouwde datatypes, wat wel erg snel is maar niet erg flexibel. Zo is in Delphi Pascal en C++ het grootste gehele getal 264 - 1 = 18 446 744 073 709 551 615. In Python kun je met gemak een getal als 64**100 invoeren. Dit is 64 tot de macht 100: een groot geheel getal. Het kan nog groter. Als je zoiets met Pascal of C++ wil doen dan moet je speciale bibliotheken gebruiken, met diverse nadelen.
Talen als Pascal en C++ gebruiken zogenaamde getypeerde variabelen. Dat wil zeggen dat je van te voren moet opgeven wat voor soort variabele je gebruikt. Deze talen zijn daar ook vaak streng in: als eenmaal een variabele een geheel getal is dan kun je daar niet zomaar een letter inzetten. Dit heeft mij in grote programma's vaak voor programmeerfouten behoed. In Python is dat anders. Een variabele krijgt een type op het moment dat hij een waarde krijgt. Je kunt dat gerust tijdens de loop van het programma veranderen. Dat is erg flexibel, maar heeft twee nadelen: je kunt gemakkelijk fouten maken en het is minder efficiënt.
Het volgende mag in Python, maar is absoluut verboden in Pascal- of C++-achtige talen:
Ik = 3
print('Ik ben nu', Ik)
Ik = 'Theo'
print('Ik ben nu', Ik)

met als uitkomst
Ik ben nu 3
Ik ben nu Theo

Blok-opdrachten in Python

In tegenstelling tot bijna alle andere talen gebruik je bij Python geen accolades of dergelijke om aan te geven dat bepaalde opdrachten bij elkaar horen. Bij Python doe je dat door in te springen. Hierdoor zien je programma's er al snel netjes uit.
Hieronder staat hoe je bijvoorbeeld de opdrachten bij een lus bij elkaar houdt:
for x in [1, 3, 5, 7]:
    print('x =', x)
    print('wortel(', x, ')=', x**(1/2))
    
print('Klaar')

Hoeveel spaties je inspringt maakt niet uit. Het mag per blok variëren, maar binnen een blok moet je hetzelfde aantal spaties inspringen. Veel Python interpreters doen dit automatisch zodra ze een dubbele punt zien. Sommige interpreters dwingen een vast aantal spaties (bijvoorbeeld 4) af.
In dit voorbeeld zie je ** staan. Dat wil zeggen "tot de macht". Als je hier (1/2) achter zet dan neem je de wortel. Machtsverheffen doe ik meestal met **, maar het kan ook met de functie pow(): pow(2, 1/2).

Functies in Python

Je kunt in Python een functie maken via het woordje def. Achter def zet je de naam van de functie en tussen haakjes de parameters die je wilt meegeven. Dat kunnen er nul of meer zijn. Vervolgens zet je een dubbele punt. Alles wat bij de functie hoort moet je inspringen. Als je een waarde wil teruggeven dan doe je dat na het woord return. Bij Python kun je meer dan één waarde teruggeven. In tegenstelling tot andere talen mag je bij de aanroep vamn een functie de naam van de variabele meegeven. Zie het voorbeeld hieronder. Dit heeft twee voordelen: je code wordt leesbaarder EN de volgorde waarop de parameters worden meegegeven is niet van belang. Als je dit niet gebruikt dan moet je wel de volgorde aanhouden die voor de functie geldt.
def Test(x, y, z):
    print(x, y, z)
    
Test(1, 2, 3)
Test(z = 1, y = 2, x = 3)

De uitvoer is
1 2 3
3 2 1

Over de brontekst

Hieronder staat de broncode (de programmatekst) van een aantal Python programma's. Je mag ze onbeperkt kopiëren en gebruiken. Om ze in het programma te krijgen waarmee jij jouw programma's ontwikkelt (bijvoorbeeld Thonny) ga je als volgt te werk: maak een nieuw leeg venster aan (vaak kan dat met CTRL-n). Selecteer de gewenste broncode (dat is de tekst op de zwarte achtergrond) en kopieer deze (CTRL-c). Plak deze vervolgens in het nieuwe, lege raam (CTRL-v). In Linux kan het kopiëren en plakken iets anders werken. Voordat je het programma kunt uitvoeren moet je het eerst opslaan onder een door jezelf te kiezen naam. Software bibliotheken kun je wel via een link downloaden, zodat je automatisch de juiste naam behoudt.

Python in de praktijk

Verderop beschrijf ik een aantal Python programma's. Het gaat mij niet om heel grote programma's, maar om programma's die ik de moeite waard vind om te delen. Ik maak al mijn programma's in principe met Thonny voor Windows (soms voor Linux). Voor de meeste programma's maakt dat niets uit, maar soms doet Thonny iets vanzelf goed wat andere programma's niet doen. Het installeren van bibliotheken is met Thonny vaak gemakkelijker dan met bijvoorbeeld Idle.
Als je NIET met Thonny werkt dan moet je zelf Python downloaden en installeren. Hierbij moet je een vinkje zetten in het vakje waarbij staat dat Python in het pad moet worden opgenomen. Als je dat niet doet dan kun je allerlei problemen verwachten.

Ik maak ook steeds vaker programma's met MicroPython, maar hiervoor maak ik aparte pagina's.

Globaal en locaal

Een globale variabele is een variabele die je overal kunt gebruiken, terwijl een locale variabele alleen gebruikt kan worden binnen een "blok". Een "blok" kan bijvoorbeeld een functie zijn. Python wil het gebruik van globale variabelen ontmoedigen, omdat het gebruik hiervan als slechte programmeertechniek wordt gezien. Of je het hier nu mee eens bent of niet, het is een feit dat Python merkwaardig (bijna onbegrijpelijk) omgaat met globale en locale variabelen. Als je een variabele in de hoofdtekst van je programma (dus niet in bijvoorbeeld een functie) een waarde geeft, dan is die variabele globaal. Je zou denken dat je deze deze variabele dus overal in een functie gewoon kunt gebruiken. Helaas is dat alleen het geval als de variabele binnen de functie nooit een nieuwe waarde krijgt. Als je een superlange functie hebt en op het eind geef je de variabele een waarde, dan wordt het ineens een locale variabele en werkt je programma misschien niet meer. Dit kun je oplossen door het woordje global. Achter global kun je een lijst met variabelen zetten, gescheiden door een komma.
def printTekst():
    print(Tekst) # goed: Tekst is een globale variabele
    
def printNieuw():
    if Tekst == '':
        print('leeg')
    else:
        print(Tekst)
    Tekst = 'Python is niet OK' # dit veroorzaakt de fout

Tekst = 'Python is ok'  
printTekst()
printNieuw()
def printTekst():
    print(Tekst) # goed: Tekst is een globale variabele
    
def printNieuw():
    global Tekst # nu gebruik je de globale variabele
    if Tekst == '':
        print('leeg')
    else:
        print(Tekst)
    Tekst = 'Python is niet OK' # geen fout, maar doet niets

Tekst = 'Python is ok'  
printTekst()
printNieuw()

Het eerste programma geeft de foutmelding
    if Tekst == '':
UnboundLocalError: local variable 'Tekst' referenced before assignment
Het tweede programma gaat goed, maar de veranderde tekst wordt niet geprint omdat deze pas wordt toegekend nadat er geprint is.

Invoer en uitvoer

Als u een waarde wil invoeren gebruikt u de functie input(). Bijvoorbeeld:
Naam = input('Wat is uw naam? ')
De tekst 'Wat is uw naam? ' komt nu (zonder aanhalingstekens) in de shell (=REPL) te staan. De bedoeling is dat u iets intypt en afsluit met een druk op de Enter toets. Vanaf nu is de door u ingevoerde naam te gebruiken in het Python programma. De functie print() gebruikt u om waarden in de shell te printen; meerdere waarde kunt u scheiden door een komma:
print('Hallo', Naam)
De functie input() geeft altijd een string terug, ook als u een cijfer heeft ingevoerd. Als u met getallen wilt rekenen dan zult u de string moeten omzetten in een geheel getal of in een drijvendekommagetal. Ik geef van beide een voorbeeld:
cijfer = int( input('Geef een geheel getal ') )
if cijfer // 2 == cijfer / 2: print(cijfer, 'is even') else: print(cijfer, 'is oneven')

Geef een geheel getal 7
7 is oneven

Ik gebruik hier // om te delen en alles achter de komma weg te laten, zo wordt 7 // 3 dus 2 en niet 2.5
getal = float( input('Van welk getal wilt u de wortel weten? ') )
print('De wortel van', getal, '=', getal ** 0.5)

Van welk getal wilt u de wortel weten? 2
De wortel van 2.0 = 1.4142135623730951

f-strings

Misschien valt het je op dat een print statement, zoals in het voorbeeld hierboven onoverzichtelijk is. Daar komt nog bij dat Thonny wel, maar sommige andere interpreters geen spaties printen na een komma. Er zijn veel manieren om dit op te lossen, maar het mooist is het gebruik van zogenaamde f-strings. Je zet gewoon de letter f meteen voor de string (dus meteen voor het aanhalingsteken). Alles wat in de string tussen accolades staat wordt nu vervangen door de waarde en de rest van de tekst wordt ongewijzigd weergegeven. Er zijn nog meer mogelijkheden met f-strings, maar de behandel ik niet. De printregel in het vorige voorbeeld wordt als f-string:
print(f'De wortel van {getal} = {getal ** 0.5}')

Je kunt f-strings overal gebruiken, dus ook in input statements:
mingetal = 0
maxgetal = 100
gok = int(input(f'Gok een getal tussen {mingetal} en {maxgetal}: '))

Gok een getal tussen 0 en 100: 

Veel gebruikte Python bibliotheken

Veel gebruikte software bibliotheken zijn: tkinter wordt automatisch samen met Python geïnstalleerd; de andere bibliotheken moet je zelf installeren

tkinter voorbeeld

Een tkinter scherm
Er is heel veel te vertellen over tkinter, teveel om hier zelfs aan te beginnen. Daarbij heeft tkinter nogal wat lastige aspecten, waardoor je zeker als beginner veel moet zoeken op internet. Ik geef daarom alleen een voorbeeld. In dit voorbeeld reken ik de diameter van een draad om van de "eenheid" gauges (uitspraak ongeveer: "geedzjes") naar mm. Het gauges systeem is erg ingewikkeld, want het hangt ervan af van over welk metaal het gaat. Hier gaat het om gewoon elektriciteitsdraad. Je kunt ditzelfde programma uiteraard makkelijk aanpassen als je andere omzettingen wil doen.
Iets over het programma: je hebt bij tkinter altijd een hoofdraam nodig. Dit wordt meestal main genoemd, maar ik noem het raam. De onderdelen krijgen als eerste parameter het onderdeel mee waar ze op worden geplaatst, dat is in dit geval meestal raam.
De objecten hebben allerlei attributen, verschillend voor het soort object. Zo zie je dat het spin object onder andere een from_ en een to hebben. Hiermee kun je het begin en eind van een reeks gehele getallen opgeven. In plaats daarvan kun je ook een lijst met bijvoorbeeld namen meegeven. Hier is heel duidelijk hoe handig het is dat je in Python de variabelen in een functie kunt benoemen. Objecten die iets moeten doen als ze worden aangeklikt krijgen een parameter command mee. Als er niets bijzonders nodig is dan kun je hierachter de naam van een functie zonder haakjes zetten. Voor geavanceerdere toepassingen is het ingewikkelder.
Als je in een tekst object, bijvoorbeeld een label, de breedte opgeeft dan is dat nooit in pixels, maar in de fontbreedte. Iets dergelijks geldt voor de hoogte. Als je toch de breedte in pixels wil opgeven, zoals ik gedaan heb voor de uitkomstlabel dan moet je een container gebruiken waarin je de label zet. De label geef je dan geen breedte mee en als eerste parameter gebruik je de naam van de container (hier frame).
Een probleem met tkinter is dat je nooit zeker weet hoe de interface eruit zal zien, dat hangt onder andere van de IDE af die je gebruikt. Het kan dus goed zijn dat jouw vensters er niet netjes uitzien. Je kunt dan alle getallen aanpassen indien gewenst. Het is gebruikelijk om de plaatsing van objecten in tkinter anders te doen, maar dat is voor dit voorbeeld net iets te ingewikkeld.
"""Vertaalt AWG (American Wire Gauge) naar millimeters"""
from tkinter import *
def Naar_mm():
    gauges = int(spin.get())
    diameter = f'{0.127*92**((36-gauges)/39):.2f}' # rond af op 2 decimalen
    tekst.set(f'diameter = {diameter} mm')
    label.update()

raam = Tk()
raam.title('Gauges naar mm')
raam.geometry('430x220')
Font = 'Times 24 bold'
var = IntVar(value = 34)
tekst = StringVar()
tekst.set('diameter = 0.16 mm')
AWG = Label(raam, text = 'AWG = ', font = Font)
AWG.place(x = 30, y = 30)
raam.update() # nodig om de juiste breedte terug te krijgen
OkKnop = Button(raam, width = 15, font = Font, height = 7, command = Naar_mm)
spin = Spinbox(raam, from_ = 10, to = 38, text = 34, font = Font, textvariable = var, width = 4, command = Naar_mm)
spin.place(x = 30 + AWG.winfo_width(), y = 30)
raam.update() # nodig om de juiste breedte terug te krijgen
gauge = Label(raam, text = 'gauge', font = Font)
gauge.place(x = 40 + AWG.winfo_width() + spin.winfo_width(), y = 30)
raam.update() # nodig om de juiste breedte terug te krijgen
frame = Frame(raam, bg = 'blue', width = 10 + AWG.winfo_width() + spin.winfo_width() + gauge.winfo_width(), height = AWG.winfo_height())
frame.place(x = 30, y = 100)
label = Label(frame, textvariable = tekst, font = Font, fg = 'white', bg = 'blue')
label.place(x = 10, y = 0)
raam.mainloop()
Dan iets over de berekening: je ziet in de functie Naar_mm() de lelijke instructie
diameter = f'{0.127*92**((36-gauges)/39):.2f}' # rond af op 2 decimalen
staan. De f'{}...' is een formatstring; hierbij geeft :.2f aan dat je twee decimalen wil zien, ook als de laatste decimaal een 0 is. Als je round(.., 2) gebruikt dan is het aantal decimalen minder dan 2 als de laatste decimaal 0 is.
Voor de omrekening heb je de volgende formule nodig: formule.

Van tekst naar spraak

Er is een bijzonder goede TTS (text to speech -- tekst naar spraak) bibliotheek voor Python. Deze kun je direct in Thonny installeren via het menu "manage plugins" (zoek naar gTTS). Als je onderstaand programma runt dan kun je horen hoe een zin in het Nederlands en in het Frans klinkt. De eerste keer dat je het programma start kan het zijn dat je gevraagd wordt om een mediaspeler te kiezen. Ik kan niet nagaan of dit bij jou ook goed zal klinken, maar bij mij klinkt dit erg goed.
from gtts import gTTS
import os, time
tts = gTTS(text = 'Goede morgen allemaal. Bent u gelukkig ondanks de avondklok?', lang = 'nl')
tts.save('test.mp3') # bewaar het geluid in test.mp3
os.system('test.mp3') # speel het geluid van test.mp3 af

time.sleep(5)
tts = gTTS(text = 'Bonjour à tous. Êtes-vous heureux malgré le couvre-feu?', lang = 'fr')
tts.save('test.mp3')
os.system('test.mp3')

Een Nextion display schrijven of lezen

Nextion (rechts) met programmer (links)
Nodig: Nextion display, programmer met 5 volt uitgang, vier jumper kabeltjes.
Op mijn Arduino pagina's beschrijf ik hoe goed de programmeerbare Nextion displays zijn. De gewenste layout maak je met de gratis Nextion editor. Hierbij kun je ook je eigen achtergrondplaatjes en dergelijke gebruiken. Er is ook een ingebouwde taal, waarmee je het scherm kunt programmeren, zodat je bijvoorbeeld door op een knop te klikken naar een volgende schermpagina kunt gaan.
Het is mogelijk variabelen en eigenschappen te veranderen vanuit een ander programma. Alleen de eigenschappen die in de Nextion editor groen zijn kun je veranderen, maar dat is vrij logisch: je kunt bijvoorbeeld niet de naam van een knop veranderen, maar wel de tekst op die knop. Omdat dit met een eenvoudige seriële verbinding gebeurt kan dat met elke programmeertaal. Ik laat het hier aan de hand van een voorbeeld zien hoe het in Python gaat. Als je dit uitgebreid wil gaan toepassen dan zul je nog zelf een aantal dingen moeten uitzoeken, maar het principe heb je dan. Gebruik niet te veel fonts, want als je tegen de geheugengrens loopt dan werkt een en ander niet meer goed.
Om onderstaand voorbeeld uit te proberen: Zet drie tekstvakken onder elkaar zoals op de foto en geef deze een achtergrondkleur. Verander hun naam in respectievelijk rood wit en blauw. Haal de default tekst weg. Zet daaronder een tekstvak met de naam t1. Maak het aantal letters in het tijdvak groter en zet daar "Nederlandse vlag" in. Om vlag in het midden te krijgen heb ik een aantal extra spaties toegevoegd, want de wrap werkt niet goed. De Nextion editor heeft een debug mogelijkheid, die erg handig is om dit te bekijken. Daaronder komt nog een knop (tekstvak mag ook) met het woord "tijd" erin; verander de naam in "tijd".
Het Nextion Editor venster. In de rode elipsen zie je de eigenschappen die veranderd mogen worden.

Over het Python programma:
Je moet eerst een verbinding maken met de programmer. Als de Nextion editor gebruikt om te uploaden via de programmer, dan kun je zien welke poort gebruikt wordt. In mijn geval is dat poort 3. Je zult dit moeten veranderen in het Python programma al je een andere poort hebt.

Uploadvernster, direct na uploaden. Er staat nog veel meer informatie dan alleen het poortnummer

Na het uploaden wordt de poort netjes gesloten, zodat je direct verder kunt gaan met je Python programma. Hieronder is de bibliotheek PySerial gebruikt, niet Serial! Een poort wordt geopend met
ser = serial.Serial('COM3', baudrate = 9600, timeout = 0.1)
Ook al wordt het programma met een baudrate van 115200 geüpload, toch werkt hier alleen een baudrate van 9600. Ik heb er ook nog een timeout ingezet voor het geval er iets mis gaat, maar dat zou in het voorbeeld niet nodig moeten zijn.
Volgens sommigen moet je voor een tekst altijd een backslash zetten, dus 't1.txt=\"Duitse vlag"', maar volgens de documentatie is dat niet nodig. Overigens doet die slash geen kwaad als je hem toch gebruikt.
Bij de instructies mag je geen spaties om het =-teken zetten. Als je binnen de Nextion editor programmeert mag je bijna nergens spaties gebruiken.
Als de Nextion vastloopt of als je opnieuw wil beginnen, haal de programmer dan even uit de USB poort en sluit hem weer aan. Mijn programmer heeft hier een drukknop voor - wel zo makkelijk.
import serial, time
from datetime import datetime
eind = b'\xff\xff\xff' # Hiermee moet elke opdracht eindigen
ser = serial.Serial('COM3', baudrate = 9600, timeout = 0.1)

# Voorbeeld andere achtergrondkleur (bco = background color)
zwart = str.encode('rood.bco=BLACK')
rood = str.encode('wit.bco=RED')
geel = str.encode('blauw.bco=YELLOW')
ser.write(zwart + eind)
ser.write(rood + eind)
ser.write(geel + eind)

# Voorbeeld van andere tekst
duits = str.encode('t1.txt="Duitse vlag"')
ser.write(duits + eind)

# Voorbeeld van digitale klok
klok = str.encode('tijd.txt=\"')
tijd = str.encode(time.strftime('%H:%M:%S', time.localtime()))
af = str.encode('"')
ser.write(klok + tijd + af + eind)

# Voorbeeld hoe je een tekstvariabele opvraagt
vraag = str.encode('get tijd.txt')
ser.write(vraag + eind)
uitvoer = ''
ser.read() # Hier wordt een p gelezen, maar daar doen we niets mee
while True:
    ch = ser.read()
    if ch == b'\xff':
        ser.read() # lees de twee b'\xff' bytes waarmee elke uitvoer wordt afgesloten
        ser.read() # dat is hier eigenlijk niet nodig omdat ik de seriele poort hierna afsluit
        break
    uitvoer += ch.decode('utf-8')
print(uitvoer)

Natuurlijk zou je graag een functie maken die automatisch een eindstring toevoegt, maar omdat dat enigszins onoverzichtelijk wordt heb ik hier vanaf gezien.

Ditheren in kleur of zwart-wit

Het kan voorkomen dat je een plaatje nodig hebt met maar weinig verschillende kleuren, bijvoorbeeld alleen zwart en wit. Je krijgt meestal geen goed resultaat als je simpelweg donkere pixels omzet in zwart en lichte in witte pixels. Beter is het om grijs te maken door zwarte en witte pixels af te wisselen. Bijna alle programma's die plaatjes kunnen omzetten naar twee kleuren kunnen dit erg goed. Als je echter meer kleuren hebt, bijvoorbeeld drie of zeven kleuren e-Paper displays of vier grijstinten dan is het lastiger om een programma te vinden die dat goed doet. Dan moet je het bestand ook nog kunnen opslaan in een vorm die je kunt gebruiken met de softwarebibliotheek waarmee je het e-PAper display aanstuurt. Met een eigen Python programma kun je beide problemen oplossen. Het resultaat is erg goed.

gans
Hier zie je een plaatje dat maar 7 kleuren bevat. Maak hem niet te klein op je scherm want dan krijg je er mogelijk een Moiré patroon overheen.
Ik heb de Python programma's die dit doen op een eigen pagina gezet, met meer uitleg, zie hier.
Je hebt de versie die een plaatje omzet in 2 bits vier grijstinten bmp nodig om een plaatje om een 4,3″ e-Paper te krijgen dat ik hierna bespreek. (Nog doen).


Maak een HTML tabel met Python Als je weleens een tabel hebt gemaakt in een html pagina, dan weet je dat dat bij grote tabellen veel werk is. Met Python is het een fluitje van een cent om tabellen te genereren. Zo heb ik alle grote tabellen in mijn pagina over bijzondere magische vierkanten eenvoudig met Python gemaakt. Het eerste Python programma slaat de html code op in een bestand, zodat je dit met copy en paste kunt overnemen in je html broncode. Doordat ik de extensie html heb gekozen kun je het bestand ook openen met een browser. Je ziet de tabel dan al, maar zonder formattering. Ik raad niet aan om formattering ook via Python weg te schrijven. Dat doe je beter in je html pagina, in de style sectie.
Tabel = [[16, 41, 36, 5, 27, 62, 55, 18],
         [26, 63, 54, 19, 13, 44, 33, 8],
         [1, 40, 45, 12, 22, 51, 58, 31],
         [23, 50, 59, 30, 4, 37, 48, 9],
         [38, 3, 10, 47, 49, 24, 29, 60],
         [52, 21, 32, 57, 39, 2, 11, 46],
         [43, 14, 7, 34, 64, 25, 20, 53],
         [61, 28, 17, 56, 42, 15, 6, 35]]

Bestand = open('Tabel.html', 'w') # Als Tabel.html al bestaat dan wordt hij overschreven!
 
Bestand.write('<table>\n') # Schrijf de tabel-tag in het bestand
for x in Tabel:
    Bestand.write('<tr>') # Schrijf de nieuwe-regel-tag in het bestand
    for y in x:
        Bestand.write('<td>' + str(y) + '</td>') # Schrijf de kolom-tag, de waarde en de eindtag in het bestand
    Bestand.write('</tr>\n') # Schrijf de regel-eind-tag in het bestand
Bestand.write('</table>\n') # Schrijf de tabel-eind-tag in het bestand

Bestand.close() # Sluit het bestand af

Hieronder zie een minimale html pagina, met een geformatteerde tabel.

Bepalen of een getal een priemgetal is

Als je wilt nagaan of een getal een priem is of niet dan hoef je niet een ingewikkelde, langzame methode te gebruiken als de zeef van Eratosthenes te gebruiken! Er bestaat een simpel algoritme voor. Ik heb dat in het onderstaande programma geïmplementeerd. Nadat het in Thonny is geladen en een keer gerund is, kun je het aanroepen met - bijvoorbeeld - IsPriem(11)
def IsPriem(N): # N is het getal dat getest moet worden
    if N < 2:
        print(N, 'is geen priemgetal')
    elif N == 2:
        print('2 is priem')
    else:
        count = N // 2
        a = 1
        while count != 0:
            a += 1
            rem = N % a
            if rem == 0:
                print(N, 'is geen priem')
                break
            count -= 1
            if count == 0:
                print(N, 'is priem')

Dit programma controleert niet of het getal N een geldig getal is.