Code-Editoren & Bewertung
Code-Editoren, die Schüler bearbeiten und im Browser ausführen können — keine Installation, kein Server, kein "installier zuerst Python". Python und JavaScript laufen beide clientseitig; SQL läuft gegen SQLite-Datenbanken pro Schüler (im nächsten Kapitel behandelt); HTML rendert in ein sandboxed Live-Vorschau-Iframe.
Diese Seite behandelt auch die drei Arten, Schülerarbeit zu bewerten: python-check (Bestehen/Nichtbestehen-Assertions auf Code, mit Punkten), automatische Freitext-Prüfung (Teilpunkte-Bewertung einer vorhergesagten Ausgabe) und <ai-feedback> (KI-Feedback zu Code, Freitext oder Stiftstrichen, die auf einem Plot oder Diagramm gezeichnet wurden). "Bewertung" meint hier Punkte — die Note von 1-6, die ein Schüler am Ende erhält, ist eine separate, von der Lehrperson gesetzte Grösse.
Grundsyntax
Füge editor nach der Sprachkennung in einem Fenced-Code-Block hinzu:
```python editor
name = "World"
print(f"Hello, {name}!")
```
Schüler sehen einen Editor mit dem Startcode, klicken auf Run, sehen die Ausgabe darunter.
HTML-Syntax
<code-editor data-language="python" data-code="print('Hello')"></code-editor>
Die HTML-Form erlaubt zusätzliche Attribute, die nicht sauber in eine Fence-Info-Zeile passen.
Unterstützte Sprachen
| Sprache | Laufzeit | Hinweise |
|---|---|---|
| Python | Pyodide + Skulpt | Automatisch: Skulpt für turtle und input(), Pyodide für alles andere |
| JavaScript | Ein sandboxed Web Worker | Modernes JS, kein DOM-Zugriff — für Algorithmen, nicht für Seiten |
| SQL | SQL.js (SQLite zu WebAssembly kompiliert) | Siehe Kapitel SQL-Editoren |
| HTML | Ein sandboxed Iframe im Browser des Schülers | Live-Vorschau-Panel neben dem Editor — für HTML-/CSS-/JS-Lektionen |
Der erste Python-Lauf lädt die Laufzeitumgebung (~5 Sekunden, danach gecacht). Nachfolgende Läufe sind sofort. JavaScript und SQL sind beim ersten Lauf fast sofort.
Zwei Python-Laufzeiten, transparent
Eduskript führt Python in einer von zwei Browser-Engines aus und wählt die richtige basierend auf deinem Code:
| Verwendetes Feature | Laufzeit | Warum |
|---|---|---|
import turtle oder from turtle import ... | Skulpt | Native asynchrone Unterbrechung für animierte Turtle-Grafiken |
Aufrufe von input("...") | Skulpt | Sauberes, synchron wirkendes input() über Skulpts Coroutinen |
| Alles andere (NumPy, pandas, matplotlib, Datei-I/O, Standardbibliothek) | Pyodide | Echtes CPython auf WebAssembly — volle Bibliotheksunterstützung |
Kein Flag zum Setzen, kein Editor-Attribut — der Editor untersucht den Code und wechselt. Schreib den Code, den du schreiben willst; die richtige Laufzeit wird geladen. Beide werden lazy vorgeladen, sobald der Schüler zu einem Editor scrollt.
Eine praktische Konsequenz: Da Skulpt ein Python-zu-JS-Compiler ist (nicht CPython), verhalten sich manche Grenzfälle bei turtle oder input() leicht anders als in Desktop-Python. Falls du auf eine Skulpt-spezifische Eigenheit stösst, vermeide die zwei Trigger-Features, dann landest du wieder bei Pyodide.
Editor-IDs (empfohlen)
Gib jedem Editor eine id. Die ID:
- Erlaubt
python-check-Blöcken, den Editor für die automatische Bewertung zu referenzieren - Liefert einen stabilen Schlüssel für die Persistenz pro Schüler (damit Umsortieren von Seiten keine Arbeit verliert)
- Identifiziert den Editor beim Tracking von Abgaben und bei der Bewertung
```python editor id="exercise-1"
def double(x):
pass # student fills in
```
Ohne explizite idDer Editor bekommt eine generierte ID basierend auf seiner Position auf der Seite. Bearbeitest du die Seite später, kann die gespeicherte Arbeit des Schülers plötzlich einem anderen Editor zugeordnet sein. Setze immer eine
idfür alles, zu dem Schüler zurückkehren werden.
IDs müssen nur innerhalb einer Seite eindeutig sein. id="loops" auf Seite A und id="loops" auf Seite B sind unabhängig.
Mehrdatei-Editoren
Für alles Komplexere als ein Einzeldatei-Skript verwende mehrere aufeinanderfolgende Blöcke mit derselben id. Jeder Block wird ein Tab im Editor.
```python editor id="rectangle" file="main.py"
from shapes import area, perimeter
w, h = 4, 7
print("Area:", area(w, h))
print("Perimeter:", perimeter(w, h))
```
```python editor id="rectangle" file="shapes.py"
def area(width, height):
return width * height
def perimeter(width, height):
return 2 * (width + height)
```
Die Blöcke müssen im Quelltext aufeinanderfolgend sein — alles dazwischen (auch nicht-passende Codeblöcke) bricht die Gruppierung auf. Das Attribut file= benennt jeden Tab; lässt du es weg, wird der erste Block zu main.py und die restlichen zu file2.py, file3.py usw.
Dasselbe Muster funktioniert für JavaScript (.js) und SQL (.sql).
Persistenz pro Schüler
Jeder Code-Editor speichert automatisch, was jeder Schüler eintippt — verknüpft mit seinem Konto und der id des Editors. Kommt er morgen zurück, ist seine Arbeit sofort da.
- Speichern — automatisch, mit Verzögerung (debounced); manueller Schnappschuss über den "Save version"-Button des Editors
- Zurücksetzen — stellt den ursprünglichen Markdown-Inhalt wieder her (aktuelle Version, nicht ein veralteter Cache)
- Versionsverlauf — vergangene Schnappschüsse ansehen, jeden davon wiederherstellen
- Sync — speichert in die Cloud, falls eingeloggt; funktioniert offline gegen IndexedDB und synct bei Wiederverbindung
Ausgeloggte Schüler erhalten nur IndexedDB-Persistenz (ihre Arbeit übersteht einen Seiten-Refresh, aber kein Löschen der Browserdaten).
Editor-Funktionen für Schüler
Innerhalb eines Code-Editors haben Schüler:
- Run-Button — Code ausführen, Ausgabe darunter sehen
- Zurücksetzen — auf das Original zurücksetzen (mit Bestätigung)
- Grösse ändern — den Trenner zwischen Editor und Ausgabe ziehen
- Schriftgrösse — Tastenkombination (
Cmd/Ctrl + +/-) - Suchen/Ersetzen —
Cmd/Ctrl + Finnerhalb des Editors - Mehrfach-Cursor —
Cmd/Ctrl + Klickfür zusätzliche Cursor - Auto-Einrückung, Klammer-Abgleich, Syntax-Highlighting
Bei Mehrdatei-Editoren zusätzlich:
- Datei hinzufügen —
+-Button neben den Datei-Tabs - Datei umbenennen — Doppelklick auf den Tab-Namen
- Datei löschen —
×-Button auf dem Tab (die letzte Datei kann nicht gelöscht werden)
Pythons input(), Ausgabe, Fehler
input() funktioniert — Schüler bekommen einen Prompt direkt über der Ausgabe. Nützlich für interaktive Übungen ("gib dein Alter ein", "rate die Zahl").
print() schreibt in das Ausgabe-Panel. Fehler (wie unabgefangene Exceptions) bekommen eingefärbte Tracebacks.
Für Python-Turtle-Grafiken funktioniert import turtle — die Ausgabe erscheint als eingebettetes Canvas über der Textausgabe.
output-only: für Figuren, nicht für Textausgabe
Füge output-only hinzu, um den Code beim Laden der Seite automatisch auszuführen und nur das Ergebnis zu zeigen — Code eingeklappt, ausklappbar. Gebaut für matplotlib-Figuren und ähnliche "hier ist die Ausgabe, so wurde sie erzeugt"-Übungen:
```python editor output-only
import matplotlib.pyplot as plt
plt.plot([1, 2, 3], [1, 4, 9])
plt.show()
```
Siehe Mathe und Funktionsplotter dafür, wann sich ein plot-Block statt eines vollen Python-Editors lohnt.
HTML-Editor mit Live-Vorschau
Verwende ```html editor für HTML-/CSS-/JS-Lektionen. Der Editor teilt sich in zwei Bereiche — Code links, ein sandboxed Iframe rechts, das sich ~500 ms nach jedem Tastendruck neu rendert.
```html editor
<style>
body { font-family: system-ui; padding: 1rem }
h1 { color: crimson }
</style>
<h1>Hallo Welt</h1>
<button onclick="alert('Klick!')">Klick mich</button>
```
Was innerhalb des Iframes funktioniert:
- Inline-Event-Handler (
onclick="..."),<script>-Blöcke und DOM-Zugriff von JavaScript aus alert(),confirm(),prompt()für interaktive Demos<form>-Submission (navigiert nicht weg — die Sandbox blockiert Top-Level-Navigation)- Externe Ressourcen: CDN-Skripte, Google Fonts, externe Bilder laden normal
Was per Design nicht funktioniert:
- Zugriff auf die übergeordnete Eduskript-Seite —
window.parent, Cookies,localStorageder Host-Site sind alle blockiert (keinallow-same-origin) - Weiterleiten des Schüler-Tabs weg von der Lektion (kein
allow-top-navigation) - Kombination mit
python-checkoder Ausführung imexam-Modus — der HTML-Editor wird nicht automatisch bewertet
Layout und Optionen
- Standardgrösse: 400 px hoch, 50/50-Horizontalteilung. Der Schüler kann den Trenner ziehen.
- Stapelung auf Mobilgeräten: unter 768 px stapeln sich die Bereiche vertikal (Editor oben, Vorschau darunter).
- Eigene Höhe:
height="600"(Pixel) in der Fence-Info-Zeile setzen. - Vollbild: der Vollbild-Button in der Toolbar nutzt die native Vollbild-API des Browsers.
```html editor height="600" id="kitten-demo"
<img src="https://placekitten.com/400/300">
```
Persistenz und Zurücksetzen verhalten sich genau wie bei den anderen Editoren — Schüleränderungen werden pro id gespeichert, und Reset stellt das Original-Markdown wieder her.
Vorerst nur eine DateiDer HTML-Editor nimmt einen Block pro Editor. Das Mehrdatei-Muster mit
file="...", das Python und JavaScript unterstützen, ist für HTML noch nicht verdrahtet — kombiniere HTML, CSS und JS in einem einzigen Block (verwende<style>und<script>inline).
Was kann Python? Was kann JavaScript?
Python (Pyodide)
- Volle Standardbibliothek (
os,sys,json,math,random,datetime,collections,reusw.) - Wissenschaftlicher Stack:
numpy,pandas,matplotlib,scipy,scikit-learn,sympy - Datei-I/O:
open()funktioniert gegen ein In-Memory-Dateisystem import turtlefür Grafiken- HTTP-Anfragen: durch Browser-CORS blockiert — funktioniert meist nur gegen denselben Origin
- Subprozesse / OS-Befehle: blockiert
JavaScript
- Volles ECMAScript 2023
console.logschreibt in die Ausgabe- Kein DOM-Zugriff (sandboxed)
- Kein
fetch()auf beliebige URLs (CORS-blockiert) - Nützlich für: Algorithmen, Datenmanipulation, JSON-Verarbeitung, Vergleiche mit Python
Für laufzeitspezifische Dinge (Datei-Uploads, Browser-APIs, Charting-Bibliotheken) verwende stattdessen ein Plugin — siehe Plugins.
Code bewerten: python-check
Kombiniere einen beliebigen Code-Editor mit einem python-check-Block, und die Seite bewertet sich selbst. Schüler klicken auf Check; der Runner führt ihren Code aus, führt deine Assertions aus und zeigt, was bestanden hat und was nicht — mit den Hinweisen, die du geschrieben hast, in der Sprache, in der du sie geschrieben hast.
Keine Bewertungs-Warteschlange. Kein "ich schau mir das nächste Woche an". Schüler bekommen Feedback in dem Moment, in dem sie dafür bereit sind.
Ein erstes Beispiel
Kombiniere einen Editor mit einem Check-Block. Der Editor braucht eine id; der Check-Block referenziert sie über for=.
```python editor id="square-it"
def square(x):
return x # student fills this in
```
```python-check for="square-it"
assert square(5) == 25, "square(5) sollte 25 zurückgeben.|Stark — square(5) = 25!"
assert square(0) == 0, "square(0) sollte 0 zurückgeben."
assert square(-3) == 9, "square(-3) sollte 9 zurückgeben (negative Zahlen im Quadrat werden positiv)."
```
Schüler sehen den Editor und einen Check-Button. Ein Klick auf Check:
- Führt den Code des Schülers aus (definiert
square) - Führt jedes
assertder Reihe nach aus - Zeigt ein Bestanden/Nicht-bestanden-Panel mit dem Ergebnis und der Meldung jeder Assertion
Der python-check-Block selbst wird Schülern nie angezeigt — sie sehen nur den Editor und die Ergebnisse.
Anatomie eines python-check
Jede Zeile ist eine Python-assert-Anweisung:
assert <expression>, "<message>"
- Der Ausdruck wird ausgewertet. Ist er wahr, besteht der Test; ist er falsch oder wirft er einen Fehler, schlägt der Test fehl.
- Die Meldung ist das, was Schüler für diesen Test sehen (mehr dazu weiter unten).
Zwischen den Asserts kann beliebiger Python-Code stehen — Variablen aufsetzen, Hilfsfunktionen aufrufen, was auch immer. Denk nur daran, dass jedes assert ein eigener Test ist.
Bestanden- und Fehlgeschlagen-Meldungen — die Pipe-Syntax
Ein einzelner Meldungsstring dient als Testname sowohl im Bestehens- als auch im Fehlerfall:
assert fn(5) == 25, "fn(5) sollte 25 zurückgeben."
Um unterschiedliche Meldungen für Bestehen und Fehlschlagen zu zeigen, trenne sie mit |:
assert fn(5) == 25, "fn(5) sollte 25 zurückgeben.|Stark — fn(5) = 25!"
# └── wird bei Fehler gezeigt ──┘└── wird bei Erfolg gezeigt ──┘
Schüler sehen "fn(5) sollte 25 zurückgeben." während es fehlschlägt, und "Stark — fn(5) = 25!" sobald es besteht. Nutze das für die schwierigeren Aufgaben, wo etwas Ermutigung ankommt. Bei trivialen Checks lässt du die Erfolgsmeldung besser weg — wenn jeder Test ein 🎉 bekommt, wird es schnell aufdringlich.
f-Strings funktionieren auch
assert ok, f"Ergebnis {actual}, erwartet {expected}.|Stark, du hast {actual}!"Die Interpolationen werden aus dem angezeigten Testnamen entfernt (durch…ersetzt), aber die gerenderte Meldung wird im Fehlerdetail angezeigt, wenn der Test fehlschlägt.
Verhaltenstests, nicht Implementierungstests
Bei offenen Aufgaben mit mehreren gültigen Lösungen teste, was die Funktion produziert — nicht wie sie strukturiert ist.
✅ Verhaltenstest:
assert "umbrella" in advise(10, True).lower(), "Sollte bei Regen einen Regenschirm erwähnen."
❌ Implementierungstest:
import inspect
assert "if raining:" in inspect.getsource(advise), "Sollte eine if-Anweisung auf raining verwenden."
Der erste lässt jeden Schüler seinen eigenen Weg finden. Der zweite bestraft jeden, der es anders löst, als du es dir vorgestellt hast.
Was du NICHT tun solltest
Anti-Muster
- Füge keine Vorab-Checks hinzu, die bei Stub-Code bestehen, wie
assert "fn_name" in globals()oderassert result is not None. Diese bestehen bevor der Schüler überhaupt etwas gemacht hat, blähen den Score von 0 % auf ~30 % auf und geben falsche Sicherheit. Fehlt die Funktion des Schülers, zeigt der Runner bereits einen klaren Fehler bei jedem Test, der sie verwendet — das reicht.- Wiederhole nicht denselben Codepfad mit unterschiedlichen Eingaben. Drei Asserts, die alle denselben Zweig treffen, verschwenden dein Score-Signal. Wähle Eingaben, die unterschiedliche Pfade abdecken (Grenzfälle, Randfälle, den offensichtlichen Hauptfall).
- Schreib keine Tests, die von der Print-Ausgabe abhängen, ausser du meinst es wirklich so. Teste Rückgabewerte, wo möglich — sie sind robuster gegenüber Formatierungsunterschieden.
- Schreib keinen Hinweis, der nur "falsch" sagt — gib konkrete, umsetzbare Hinweise. Die Fehlermeldung ist das Einzige, was Schüler sehen, wenn sie feststecken.
Turtle-Übungen
Turtle-Zeichnungen lassen sich nicht mit einem einfachen assert result == ... prüfen — es gibt keinen einzelnen Rückgabewert. Drei Hilfsfunktionen vergleichen stattdessen gezeichnete Pfade:
turtle_solution_matches(solution_code, match_colors=False)(bevorzugt) — führt eine von dir vorgegebene Referenzlösung durch denselben Aufzeichnungs-Stub aus und vergleicht die Menge der gezeichneten Segmente. Translations- und rotationstolerant.match_colors=Trueverlangt zusätzlich passende Stiftfarben pro Segment.turtle_matches(expected_segments)— Vergleich gegen eine explizite Segmentliste.turtle_path_matches(expected_path)— Vergleich gegen einen expliziten Pfad.
Lange Lösungsstrings in eine Setup-Variable packen, dann auf den Match prüfen:
Optionale Attribute
| Attribut | Wirkung |
|---|---|
for="<editor-id>" | Verknüpft den Check mit einem bestimmten Editor (erforderlich) |
points="N" | Score-Gewicht (Standard: 1 Punkt pro Test) |
max-checks="N" | Begrenzt, wie oft ein Schüler Check ausführen kann (nützlich bei Prüfungen — verhindert Brute-Force) |
exam-Modus: stille Bewertung
Füge exam zur Fence-Info-Zeile des Editors hinzu, und er kombiniert sich mit python-check für stille Bewertung — der Schüler führt seinen Code aus, sieht aber nie Bestanden/Nicht-bestanden-Feedback, nur dass er gelaufen ist. Verwende das für Prüfungen; der Standard (ohne exam) zeigt Feedback nach jedem Check-Klick und ist für Übung gedacht, nicht für Prüfungen.
Der Bewertungsablauf für Schüler
- Schüler schreibt Code in den Editor
- Klickt auf Check (neben Run)
- Sieht ein Panel mit jedem Test als Zeile:
- ✅ grün, wenn bestanden (mit der Erfolgsmeldung, falls geschrieben)
- ❌ rot, wenn fehlgeschlagen (mit Fehlermeldung + Fehler-Trace)
- Score angezeigt als
bestanden/gesamt(z.B.3/5) - Schüler korrigiert den Code, klickt erneut auf Check
Das python-check-Panel bleibt über Sitzungen hinweg erhalten — Schüler sehen ihr letztes Ergebnis, wenn sie zur Seite zurückkommen.
Was du als Lehrperson siehst
Für Schüler, die bei einer Klasse eingeloggt sind:
- Abgaben-Oberfläche (
Dashboard → Classes → Submissions) — sieh den letzten Score und Code jedes Schülers - Detail pro Schüler — sieh ihren Code im selben Editor, den sie benutzt haben, führ ihn selbst aus
- Numerische Überschreibungen — trage einen manuellen Score ein, der das automatisch bewertete Ergebnis überschreibt
- Kommentare — hinterlasse Rich-Text-Feedback pro Abgabe oder pro Codeblock
Automatisch bewertete python-check-Ergebnisse erscheinen neben deiner manuellen Durchsicht, sodass du auf einen Blick siehst, wer alle Checks bestanden hat und wer einen genaueren Blick braucht.
Freitext bewerten: predict-output
python-check bewertet Code. Für Fragen, bei denen der Schüler vorhersagt, was Code ausgeben würde — ohne ihn auszuführen — verwende die Freitext-Auto-Check-Variante von <question type="text">: gib ihr einen ```expected-Block statt <answer>-Kindern, und sie bewertet die getippte Vorhersage des Schülers gegen diesen erwarteten Text mit einem Diff, wobei Teilpunkte statt eines strikten Bestanden/Nicht-bestanden vergeben werden.
<question id="predict-loop" type="text" points="2">
Was gibt dieser Code aus?
```python
for i in range(3):
print(i * 2)
```
```expected ignore-whitespace
0
2
4
```
</question>
- Der
```expected-Block braucht eine Leerzeile davor innerhalb des<question>-Tags. - Flags am Fence:
ignore-case,ignore-whitespace. points="2"setzt den Maximal-Score; Teilpunkte werden basierend darauf vergeben, wie nahe der Diff ist.- Feedback (der Diff) ist standardmässig vor Schülern verborgen, sowohl bei Prüfungen als auch bei Übungen — füge
showFeedback="true"am<question>-Tag hinzu, um es während des Versuchs anzuzeigen. Lehrpersonen sehen es beim Bewerten immer.
Das ist ein anderer Mechanismus als python-check: python-check führt den Code des Schülers aus; predict-output bewertet eine schriftliche Vorhersage des Schülers darüber, was Code tut — gut, um zu testen, ob er die Ausführung nachvollziehen kann, nicht nur ob er funktionierenden Code produziert.
Offene Antworten bewerten: ai-feedback
Für Arbeiten ohne eine einzige richtige Antwort, gegen die man diffen könnte — Freitext-Erklärungen, offener Code, eine handgezeichnete Skizze — schickt <ai-feedback> die Arbeit des Schülers an ein Vision-Modell und liefert Feedback zurück statt einen Score:
<ai-feedback prompt="Prüfe, ob die Erklärung des Schülers korrekt zwischen einem Parameter und einem Argument unterscheidet. Weise bei Verwechslung konkret darauf hin." label="Meine Antwort prüfen" ></ai-feedback>
prompt(erforderlich) — deine Anweisungen an die KI, z.B. worauf sie achten und wie streng sie sein sollid— optional; mehrere<ai-feedback>-Tags auf einer Seite werden ohne Angabe anhand ihrer Position den Prompts zugeordnetlabel— der Button-Text, der Schülern angezeigt wird (Standard ist ein generisches "Check")
Was gesendet wird: die Stiftstriche des Schülers im umgebenden h1-/h2-/h3-Abschnitt, als Bild gerendert, plus das Markdown dieses Abschnitts — so kann sie einen Plot, ein Moleküldiagramm oder den Code eines Editors zusammen mit allem, was darauf gezeichnet wurde, sehen. Einen Screenshot einzufügen (Hover-Box, Ctrl+V) funktioniert als alternative Eingabe, z.B. für Arbeit, die ausserhalb von Eduskript gemacht wurde.
Erfordert, dass der Schüler eingeloggt ist, und ist pro Schüler ratenlimitiert. Anders als python-check und predict-output erzeugt das keinen numerischen Score — es ist Feedback, gedacht um einem Schüler vor der Abgabe zu helfen, nicht eine Bewertung.
Editor- und Bewertungs-Spickzettel
| Ziel | Syntax |
|---|---|
| Eigenständiger Python-Editor | ```python editor |
| Eigenständiger JavaScript-Editor | ```javascript editor |
| HTML-Editor mit Live-Vorschau | ```html editor |
| Höherer HTML-Editor | ```html editor height="600" |
| Persistenter Editor (empfohlen) | ```python editor id="my-stable-id" |
| Mehrdatei-Editor (mehrere Blöcke, gleiche id) | ```python editor id="x" file="main.py" |
| Datei-Tabs ausblenden (Einzeldatei-Modus) | ```python editor single |
| Nur-Figur-Editor | ```python editor output-only |
| Stille Prüfungsbewertung | ```python editor exam (kombiniert mit python-check) |
| HTML-Formular mit eigenen Attributen | <code-editor data-language="python" data-id="x" data-code="..."> |
| Code mit Assertions bewerten | Editor id="x", dann ```python-check for="x" |
| Unterschiedliche Bestanden-/Fehler-Meldungen | assert ok, "Fehlermeldung.|Erfolgsjubel!" |
| Score-Gewichtung | python-check for="x" points="10" |
| Versuche begrenzen (Prüfungskontext) | python-check for="x" max-checks="5" |
| Turtle-Zeichnungscheck | assert turtle_solution_matches(solution), "..." |
| Vorhergesagte Ausgabe bewerten | <question type="text" points="2"> + ```expected-Block |
| Predict-output-Feedback live anzeigen | <question type="text" showFeedback="true"> |
| KI-Feedback zu offenen Aufgaben | <ai-feedback prompt="..." label="..." ></ai-feedback> |