Eindproject · PyScript · Python in je eigen website
Python in je website met PyScript
Je hebt geleerd hoe je functies schrijft in Python. Nu ga je die functies laten werken op een echte website: een knop op je pagina, en Python rekent het antwoord uit. Daar hebben we PyScript voor.
§1Wat is PyScript?
Een browser begrijpt normaal drie talen: HTML (wat er op de pagina staat), CSS (hoe het eruitziet) en JavaScript (wat er gebeurt). Python hoort daar niet bij.
PyScript is een klein hulpmiddel dat je in je HTML laadt met twee regels. Daarna kan de browser ook Python uitvoeren. Je hoeft niets te installeren — het komt gewoon van internet, net als een lettertype.
index.html
De inhoud: koppen, invoervelden, knoppen.
stijl.css
De opmaak: kleuren, lettertypes, afstanden.
main.py
Het rekenwerk: jouw wiskundige functies in Python.
PyScript is de lijm ertussen: als iemand op een knop klikt, roept het jouw Python-functie aan en zet het antwoord terug op de pagina.
§2Zo ziet het eruit — probeer maar
Dit is een complete mini-website van drie bestanden. Typ een getal en klik op Bereken. Het rekenwerk gebeurt écht in Python. (Even geduld: PyScript heeft een paar seconden nodig om te laden.)
Zet deze twee regels in de <head> van je pagina. Verder niets. Nu kan je pagina Python uitvoeren.
<!-- PyScript laden: hierdoor kan de browser Python uitvoeren -->
<link rel="stylesheet" href="https://pyscript.net/releases/2026.7.3/core.css">
<script type="module" src="https://pyscript.net/releases/2026.7.3/core.js"></script>
Stap 2Drie dingen op de pagina, elk met een id
Voor elke functie zet je in je HTML een invoerveld, een knop en een plek voor de uitvoer. Elk krijgt een eigen id — een naamkaartje, zodat Python weet welk element hij bedoelt.
Die laatste regel zegt: "voer het bestand main.py uit als Python". Let op type="py" — dat is het verschil met een gewoon script.
Stap 3De Python-code: berekening + knop-functie
In main.py schrijf je per wiskundige functie twee delen. Deel A is gewone Python zoals in les 5. Deel B is de koppeling met de knop — en die ziet er voor elke functie hetzelfde uit.
from pyscript import web, when
# DEEL A: de berekening — gewone Pythondeffaculteit(n):
uitkomst = 1for getal inrange(1, n + 1):
uitkomst = uitkomst * getal
return uitkomst
# DEEL B: de knop-functie — draait bij een klik op #knop-faculteit@when("click", "#knop-faculteit")
defknop_faculteit(event):
n = int(web.page["invoer-faculteit"].value) # 1. lees invoer
antwoord = faculteit(n) # 2. reken uit
web.page["uitvoer-faculteit"].innerText = str(antwoord) # 3. toon antwoord
Deel B doet altijd dezelfde drie dingen:
Lees de invoer.web.page["invoer-…"] is het element met die id; .value geeft de tekst uit het invoerveld. Dat is altijd een str, dus zet je hem om met int() of float().
Reken uit. Roep gewoon je functie uit Deel A aan.
Toon het antwoord..innerText = … zet tekst in het element. Maak er eerst een str van met str().
De regel @when("click", "#knop-faculteit") boven de functie betekent: "voer deze functie uit als er op de knop met id knop-faculteit wordt geklikt". Meer koppeling is er niet.
🔮 Voorspel de uitvoer
In het invoerveld staat 5. Iemand vergeet de omzetting met int(). Wat komt er op de pagina te staan?
n = web.page["invoer-faculteit"].value
web.page["uitvoer-faculteit"].innerText = n + n
55
Geen 10! .value geeft áltijd een str — ook als er een getal in het veld staat. En "5" + "5" plakt tekst aan elkaar, precies zoals je in les 2 zag. Wil je rekenen, zet de invoer dan eerst om met int() of float().
§3bDe drie bestanden, helemaal
Dit is precies de code van het voorbeeld uit §2. Klap open, lees, kopieer. Elk bestand staat vol met opmerkingen die uitleggen wat waar hoort.
index.html — volledige code
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mijn wiskunde-website</title>
<!-- 1. Onze eigen opmaak -->
<link rel="stylesheet" href="stijl.css">
<!-- 2. PyScript laden: hierdoor kan de browser Python uitvoeren -->
<link rel="stylesheet" href="https://pyscript.net/releases/2026.7.3/core.css">
<script type="module" src="https://pyscript.net/releases/2026.7.3/core.js"></script>
</head>
<body>
<h1>Mijn wiskunde-website</h1>
<p>Typ een getal, klik op de knop, en Python rekent het uit.</p>
<!-- ===== Functie 1: faculteit ===== -->
<section class="functie">
<h2>Faculteit</h2>
<p>Bijvoorbeeld: 5! = 5 × 4 × 3 × 2 × 1 = 120</p>
<input id="invoer-faculteit" type="number" value="5">
<button id="knop-faculteit">Bereken</button>
<p id="uitvoer-faculteit" class="uitvoer">…</p>
</section>
<!-- ===== Functie 2: wortel benaderen ===== -->
<section class="functie">
<h2>Wortel benaderen</h2>
<p>Bijvoorbeeld: wortel(2) ≈ 1.4142</p>
<input id="invoer-wortel" type="number" value="2">
<button id="knop-wortel">Bereken</button>
<p id="uitvoer-wortel" class="uitvoer">…</p>
</section>
<!-- ===== Functie 3: Pythagoras — TWEE invoervelden ===== -->
<section class="functie">
<h2>Stelling van Pythagoras</h2>
<p>Twee rechthoekszijden erin, de schuine zijde eruit: c = √(a² + b²)</p>
<label for="invoer-pythagoras-a">a =</label>
<input id="invoer-pythagoras-a" type="number" value="3">
<label for="invoer-pythagoras-b">b =</label>
<input id="invoer-pythagoras-b" type="number" value="4">
<button id="knop-pythagoras">Bereken</button>
<p id="uitvoer-pythagoras" class="uitvoer">…</p>
</section>
<!-- ===== Functie 4: jouw functie hier =====
Kopieer een <section> hierboven en verander de id's:
invoer-... knop-... uitvoer-...
Meer invoervelden nodig? Geef elk veld een eigen id,
zoals invoer-pythagoras-a en invoer-pythagoras-b hierboven.
Gebruik precies dezelfde id's in main.py.
-->
<!-- 3. Onze Python-code koppelen -->
<script type="py" src="./main.py"></script>
</body>
</html>
stijl.css — volledige code
/* stijl.css — de opmaak van de website.
Hier mag je alles aanpassen: kleuren, lettertype, afstanden.
De Python-code werkt gewoon door, wat je hier ook verandert. */
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 40px auto;
padding: 0 20px;
background: #F7F9FC;
color: #1D2635;
}
h1 {
color: #2F6FDE;
}
/* Elke functie krijgt zijn eigen kaartje */
.functie {
background: white;
border: 2px solid #E3E8F0;
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
}
input {
font-size: 16px;
padding: 8px;
width: 120px;
}
button {
font-size: 16px;
padding: 8px 16px;
background: #2F6FDE;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
}
button:hover {
background: #1F55B5;
}
/* Het antwoord dat Python teruggeeft */
.uitvoer {
font-family: monospace;
font-size: 18px;
font-weight: bold;
color: #0CA678;
}
/* Labels bij functies met meerdere invoervelden */
label {
font-weight: bold;
margin-right: 4px;
}
input {
margin-right: 10px;
}
main.py — volledige code
# ============================================================
# main.py — hier staat al jouw Python-code
#
# Elke wiskundige functie bestaat uit 2 delen:
# DEEL A: de echte berekening (gewone Python, zoals in les 5)
# DEEL B: de "knop-functie" die de website aan Python koppelt
#
# Wil je een nieuwe functie toevoegen? Kopieer een blok
# (DEEL A + DEEL B) en pas de namen aan. Meer hoef je niet te doen.
# ============================================================
from pyscript import web, when
# ------------------------------------------------------------
# 1. FACULTEIT voorbeeld: 5! = 5 * 4 * 3 * 2 * 1 = 120
# ------------------------------------------------------------
# DEEL A: de berekening
def faculteit(n):
uitkomst = 1
for getal in range(1, n + 1):
uitkomst = uitkomst * getal
return uitkomst
# DEEL B: de knop-functie
# - @when("click", "#knop-faculteit"): draait bij een klik op die knop
# - web.page["invoer-faculteit"]: het invoerveld met die id
# - web.page["uitvoer-faculteit"]: de plek waar het antwoord komt
@when("click", "#knop-faculteit")
def knop_faculteit(event):
n = int(web.page["invoer-faculteit"].value)
antwoord = faculteit(n)
web.page["uitvoer-faculteit"].innerText = str(n) + "! = " + str(antwoord)
# ------------------------------------------------------------
# 2. WORTEL BENADEREN voorbeeld: wortel(2) ≈ 1.4142
# (Methode van Heron: begin met een gok en verbeter die 20 keer)
# ------------------------------------------------------------
# DEEL A: de berekening
def wortel(x):
if x == 0: # anders zouden we straks door 0 delen
return 0
gok = x / 2
for i in range(20):
gok = (gok + x / gok) / 2
return gok
# DEEL B: de knop-functie
@when("click", "#knop-wortel")
def knop_wortel(event):
x = float(web.page["invoer-wortel"].value)
antwoord = wortel(x)
web.page["uitvoer-wortel"].innerText = "wortel(" + str(x) + ") ≈ " + str(round(antwoord, 4))
# ------------------------------------------------------------
# 3. STELLING VAN PYTHAGORAS — TWEE INVOERVELDEN
# Schuine zijde c van een rechthoekige driehoek: c = wortel(a^2 + b^2)
# ------------------------------------------------------------
# DEEL A: de berekening
# Twee invoervelden betekent simpelweg: twee parameters.
def schuine_zijde(a, b):
return wortel(a * a + b * b) # we hergebruiken onze eigen wortel-functie
# DEEL B: de knop-functie
# Voor elk invoerveld één regel erbij. Verder verandert er niets.
@when("click", "#knop-pythagoras")
def knop_pythagoras(event):
a = float(web.page["invoer-pythagoras-a"].value)
b = float(web.page["invoer-pythagoras-b"].value)
antwoord = schuine_zijde(a, b)
web.page["uitvoer-pythagoras"].innerText = "c = " + str(round(antwoord, 4))
# ------------------------------------------------------------
# 4. JOUW FUNCTIE HIER
# Kopieer blok 1, 2 of 3, en verander:
# - de naam van de functie (DEEL A)
# - de id's: knop-..., invoer-..., uitvoer-... (DEEL B)
# Meer invoervelden nodig? Zie blok 3: één extra regel per veld.
# Vergeet niet dezelfde id's in index.html te gebruiken!
# ------------------------------------------------------------
§3cMeer dan één invoerveld
Niet elke functie heeft genoeg aan één getal. De stelling van Pythagoras heeft er twee nodig (a en b), de abc-formule zelfs drie. Goed nieuws: er verandert bijna niets. De regel is simpel:
Eén invoerveld extra = één id extra in de HTML + één regel extra in Deel B + één parameter extra in Deel A.
HTMLElk veld zijn eigen id
Geef de velden een duidelijke naam: invoer-pythagoras-a en invoer-pythagoras-b. De knop en de uitvoer blijven met z'n tweeën — één knop rekent alles uit.
Deel A krijgt twee parameters in plaats van één. In Deel B lees je gewoon twee velden uit — de rest is identiek aan §3.
# DEEL A: twee getallen erin, één antwoord eruitdefschuine_zijde(a, b):
returnwortel(a * a + b * b)
# DEEL B: één leesregel per invoerveld@when("click", "#knop-pythagoras")
defknop_pythagoras(event):
a = float(web.page["invoer-pythagoras-a"].value) # veld 1
b = float(web.page["invoer-pythagoras-b"].value) # veld 2
antwoord = schuine_zijde(a, b) # beide meegeven
web.page["uitvoer-pythagoras"].innerText = "c = " + str(round(antwoord, 4))
a = 3, b = 4 → c = 5.0
Deze functie draait live in het voorbeeld hierboven (§2) — probeer maar met a = 3 en b = 4.
Nog meerDrie invoervelden: de abc-formule
Precies hetzelfde trucje, nu met drie velden invoer-abc-a, invoer-abc-b en invoer-abc-c. Deze functie geeft bovendien tekst terug in plaats van een getal — dat mag prima, want op de pagina komt het toch als tekst te staan.
# DEEL A: drie getallen erin, een zin eruitdefabc_formule(a, b, c):
discriminant = b * b - 4 * a * c
if discriminant < 0:
return"geen oplossingen"if discriminant == 0:
return"x = " + str(-b / (2 * a))
x1 = (-b + wortel(discriminant)) / (2 * a)
x2 = (-b - wortel(discriminant)) / (2 * a)
return"x = " + str(x1) + " of x = " + str(x2)
# DEEL B: drie velden = drie leesregels@when("click", "#knop-abc")
defknop_abc(event):
a = float(web.page["invoer-abc-a"].value)
b = float(web.page["invoer-abc-b"].value)
c = float(web.page["invoer-abc-c"].value)
web.page["uitvoer-abc"].innerText = abc_formule(a, b, c)
a = 1, b = -3, c = 2 → x = 2.0 of x = 1.0
Denk hieraan
De volgorde telt: schuine_zijde(a, b) stopt het eerste getal in a en het tweede in b. Geef je ze omgekeerd mee, dan rekent Python vrolijk verder met de verkeerde waarden. En vergeet niet elk veld apart om te zetten met float() of int() — .value is altijd str.
§4Zelf een functie toevoegen — het recept
Wil je bijvoorbeeld een functie is_priem toevoegen? Kopieer, hernoem, klaar:
Kopieer in index.html een <section> en verander de id's in invoer-priem, knop-priem, uitvoer-priem. Heb je meer getallen nodig? Kopieer het Pythagoras-blok en gebruik invoer-priem-a, invoer-priem-b, … (zie §3c).
Kopieer in main.py een blok (Deel A + Deel B).
Schrijf in Deel A je eigen berekening: def is_priem(n): …
Vervang in Deel B de drie id's door precies dezelfde namen als in stap 1, en roep je nieuwe functie aan.
Ververs de pagina en test.
Meest gemaakte fout
De id in de HTML en de id in Python moeten exact gelijk zijn — let op hoofdletters en streepjes. Bij @when staat er een # voor ("#knop-priem"), bij web.page[…] niet ("knop-priem"). knop-priem ≠ knop_priem. En elke id mag maar één keer voorkomen op de pagina.
§5Goed om te weten
Makkelijkst: pyscript.com
pyscript.com is een gratis online editor van de makers van PyScript. Je hoeft niets te installeren:
Maak een account en klik op New project.
Je krijgt index.html, main.py en pyscript.toml. Plak de code uit §3b in index.html en main.py; voeg een nieuw bestand stijl.css toe.
Klik op Run (▶). Klaar — je site heeft meteen een link die je kunt delen.
pyscript.toml mag je leeg laten; die heb je alleen nodig als je extra pakketten wilt.
Op je eigen computer
Open index.html niet door erop te dubbelklikken — dan mag de browser main.py niet inlezen. Gebruik in VS Code de extensie Live Server (rechtermuisknop → Open with Live Server), of start in de map van je project:
python -m http.server
en ga naar http://localhost:8000.
Als het niet werkt
Druk op F12 en kijk in het tabblad Console. Python-foutmeldingen (bijv. een NameError) staan daar, net als in Thonny of IDLE. Op pyscript.com zie je ze onder je preview.
Werkt de knop nog niet? PyScript laadt 2–5 seconden. Wacht even en probeer opnieuw.
Meer weten?
Alles op deze pagina komt uit de officiële documentatie:
Alles wat je in les 1 t/m 5 leerde werkt gewoon: if, for, while, lijsten, import math. Alleen input() gebruik je niet — het invoerveld op de pagina neemt die rol over. En print() zie je in de Console (F12), niet op de pagina; gebruik .innerText om iets te tonen.
§6Zo kan een afgeronde site eruitzien
Tot slot een compleet voorbeeld ter inspiratie: een site met een menubalk, een home-knop en drie rekenmachines. Precies dezelfde bouwstenen als hierboven — alleen wat netter aangekleed met CSS.
Faculteit — één invoerveld (§3)
Pythagoras — twee invoervelden (§3c)
Euro's omrekenen — één invoerveld, vijf uitvoerplekken tegelijk
Die laatste laat een handige truc zien: één knop kan net zo veel plekken op de pagina vullen als je wilt. Je herhaalt gewoon de regel web.page["…"].innerText = … voor elk vakje, of je loopt er met een for-lus overheen.