====== Erste Skripte ======
[[python| ☚ zurück]]
//In diesem Abschnitt geht es darum zu lernen, wie man Python-Skripte erstellt und startet. Ausgehend von einem ersten einfachen Beispiel entwickeln wir im zweiten Beispiel das Programm weiter und zeigen, wie durch das Anlegen einer Projektstruktur (und von Modulen) eine professionelle Arbeitsweise möglich wird. Nach dem Durcharbeiten dieser Seite kann mit den eigentlichen Projekten begonnen werden.//
* Einfache Python-Skripte
* Erstellen und Ausführen von Python-Skripten
* Einbinden und Gebrauch von Modulen
* Projektstruktur und Arbeiten mit mehreren Dateien
====== Example 1: reflexio ======
**Aufgabe - "Schnell, schneller, am schnellsten"**
Schreibe ein Python-Programm (''reflexio''), das Reaktionszeiten messen kann.
* Beim Start soll eine kleine Anleitung erscheinen.
* Anschließend soll der User möglichst schnell reagieren, um die Messung zu stoppen.
* Das Ergebnis soll auf der Kommandozeile sichtbar sein.
===== Quellcode =====
#!/usr/bin/env python3
# Testet die Reaktionszeit
# @author: DEIN NAME
# @version: 1.0
# @usage: ./reflexio.py
import time
import random
VERSION = "This is reflexio v.1.0"
def main():
print(VERSION)
print("============== ANLEITUNG ================================")
print("(1) Drücke 'ENTER', um die Messung zu starten.")
print("(2) Drücke 'ENTER', sobald die Meldung 'JETZT' erscheint!")
print("==========================================================")
print("")
input()
print("Status: ...Messung läuft\n")
wartezeit = random.uniform(2, 6)
time.sleep(wartezeit)
print("JETZT!")
start = time.time()
input()
ende = time.time()
reaktion = ende - start
print("Status: ...Messung beendet")
print(f"Deine Reaktionszeit: {reaktion:.3f} Sekunden")
if __name__ == "__main__":
main()
===== Programm ausführen =====
Damit ein Python-Skript per './reflexio' ausführbar ist, müssen die unten aufgeführten Punkte erfüllt sein.
- Erste Zeile (**Shebang**) in die Datei einfügen: ''#!/usr/bin/env python3''
- Datei ausführbar machen: ''chmod +x reflexio''
- Starten: .''/reflexio''
====== Example 2: reflexio-advanced ======
**Aufgabe – „Schnell, schneller, am schnellsten“**
Schreibe ein Python-Programm (''reflexio-advanced''), das Reaktionszeiten misst, diese sammelt und in einer gemeinsamen Datei speichert. Auf diese Weise soll beispielsweise der Mittelwert vieler einzelner Messungen berechnet werden können.
* Beim Programmstart sollen folgende Optionen ausgewählt werden können:
* Messen
* Statistik
* Reset
* Hilfe
* Beenden
* **Messen:** Bei einer Einzelmessung soll der User möglichst schnell reagieren, um die Messung zu stoppen.
* Das Ergebnis der Einzelmessung soll auf der Kommandozeile sichtbar sein.
* Zusätzlich wird der aktuelle Durchschnitt aller gespeicherten Messungen angezeigt.
* **Statistik:** Anzeige der Anzahl gespeicherter Messwerte sowie des aktuellen Durchschnitts.
* Alle Messungen sollen in einer gemeinsamen Datei gespeichert werden.
* **Reset:** Der User soll die Möglichkeit haben, alle gespeicherten Messwerte zurückzusetzen (Reset der Datei).
* **Hilfe:** Anzeige einer kurzen Anleitung zur Bedienung des Programms.
===== Programmstruktur anlegen =====
==== Hauptverzeichnis des Projekts: reflexio-advanced ====
pi@raspi88:~/devel/projects/reflexio_advanced $ pwd
/home/pi/devel/projects/reflexio_advanced
==== Programmstruktur ====
└── reflexio_advanced # Projektverzeichnis
│
├── data # Ordner für die Messwerte (messwerte.txt)
└── src # Ordner für den Quellcode
├── core # core-Verzeichnis
│ ├── __init__.py # Erforderlich für Python!
│ ├── utility.py # Hilfsfunktionen
│ └── logic.py # Programm-Logik
└── reflexio_advanced.py # Main Programm
===== Quellcode =====
==== ohne Programmstruktur ====
Der untenstehende Code funktioniert, wird im Folgenden jedoch modularisiert.
Er ist alles andere als elegant – so etwas nennt man auch **Spaghetti-Code**.
Der Code ist
- sehr unübersichtlich und daher fehleranfällig,
- nicht gut wiederverwendbar,
- schwer zu debuggen, falls etwas nicht stimmt.
Der Code – insbesondere die Funktionen – sollen ebenfalls dokumentiert werden, was im Kurs gezeigt wird.
++++ ohne Programmstruktur |
#!/usr/bin/env python3
import time
import random
import os
VERSION = "This is reflexio-advanced v1.0"
DATA_FILENAME = "messwerte.txt"
DATA_DIR = "data"
def main():
print(VERSION)
# --- Beginn get_file() ---
base_dir = os.path.dirname(__file__)
data_path = os.path.join(base_dir, DATA_DIR)
os.makedirs(data_path, exist_ok=True)
file_path = os.path.join(data_path, DATA_FILENAME)
# --- Ende get_file() ---
while True:
# --- Beginn show_menu() ---
print("\n---------------------------------------------------------")
print("m - Messen")
print("s - Statistik anzeigen")
print("r - Reset")
print("h - Hilfe")
print("x - Beenden")
print("---------------------------------------------------------")
# --- Ende show_menu() ---
choice = input("Eingabe: ").strip().lower()
# =====================================================
# MESSEN
# =====================================================
if choice == "m":
# --- Beginn start_measurement() ---
print("\nDrücke 'ENTER', um die Messung zu starten.")
input()
print("Status: Warte auf das Signal...\n")
time.sleep(random.uniform(2, 6))
print("JETZT!")
start = time.perf_counter()
input()
end = time.perf_counter()
reaction_time = end - start
# --- Ende start_measurement() ---
print("Status: Messung beendet")
print(f"Reaktionszeit: {reaction_time:.3f} Sekunden")
# --- Beginn save_value() ---
with open(file_path, "a") as f:
f.write(f"{reaction_time}\n")
# --- Ende save_value() ---
# --- Beginn load_values() ---
if os.path.exists(file_path):
with open(file_path, "r") as f:
values = [float(line.strip()) for line in f if line.strip()]
else:
values = []
# --- Ende load_values() ---
# --- Beginn calculate_average() ---
if values:
avg = sum(values) / len(values)
print(f"Anzahl Messwerte: {len(values)}")
print(f"Durchschnitt: {avg:.3f} Sekunden")
# --- Ende calculate_average() ---
# =====================================================
# STATISTIK
# =====================================================
elif choice == "s":
# --- Beginn load_values() ---
if os.path.exists(file_path):
with open(file_path, "r") as f:
values = [float(line.strip()) for line in f if line.strip()]
else:
values = []
# --- Ende load_values() ---
if not values:
print("Es sind noch keine Messwerte vorhanden.")
else:
# --- Beginn calculate_average() ---
avg = sum(values) / len(values)
print(f"Anzahl Messwerte: {len(values)}")
print(f"Durchschnitt: {avg:.3f} Sekunden")
# --- Ende calculate_average() ---
# =====================================================
# RESET
# =====================================================
elif choice == "r":
# --- Beginn reset_data() ---
if os.path.exists(file_path):
os.remove(file_path)
print("Alle Messwerte wurden gelöscht.")
else:
print("Es sind keine gespeicherten Messwerte vorhanden.")
# --- Ende reset_data() ---
# =====================================================
# HILFE
# =====================================================
elif choice == "h":
# --- Beginn show_help() ---
print("\n====================== ANLEITUNG ======================")
print("(1) Wähle 'm', um eine Messung zu starten.")
print("(2) Drücke 'ENTER', um die Messung zu beginnen.")
print("(3) Warte, bis die Meldung 'JETZT!' erscheint.")
print("(4) Drücke sofort 'ENTER', um zu stoppen.")
print("")
print("s - Statistik anzeigen")
print("r - Messwerte zurücksetzen")
print("h - Diese Hilfe anzeigen")
print("x - Programm beenden")
print("=========================================================")
# --- Ende show_help() ---
# =====================================================
# BEENDEN
# =====================================================
elif choice == "x":
print("\nProgramm beendet.")
break
else:
print("Ungültige Eingabe. Mit 'h' Hilfe anzeigen.")
if __name__ == "__main__":
main()
++++
==== mit Programmstruktur ====
Der Code ist nun modularisiert.
Er ist deutlich übersichtlicher und lässt sich dadurch besser warten und verstehen.
Außerdem können z.B. die Module wiederverwendet werden – ebenso kann das Utility-Modul als Vorlage für andere Programme dienen.
Die Dokumentation der Methoden (Docstrings) fehlt hier übrigens noch.
* **Logik** Enthält die „Game-Logik“, also alles, was mit dem Messen und Speichern der Reaktionszeiten zu tun hat.
* **Utility** Enthält Hilfsfunktionen, die nicht direkt zur Logik gehören, aber vom Programm benötigt werden.
* **Hauptprogramm** Das eigentliche Programm. Hier sollte man starten, um die Funktionsweise des Programms zu überprüfen.
++++ mit Programmstruktur |
==== Logik ====
import time
import random
import os
def start_measurement():
print("\nDrücke 'ENTER', um die Messung zu starten.")
input()
print("Status: Warte auf das Signal...\n")
time.sleep(random.uniform(2, 6))
print("JETZT!")
start = time.perf_counter()
input()
end = time.perf_counter()
return end - start
def save_value(file_path, value):
with open(file_path, "a") as f:
f.write(f"{value}\n")
def load_values(file_path):
if not os.path.exists(file_path):
return []
values = []
with open(file_path, "r") as f:
for line in f:
line = line.strip()
if line:
values.append(float(line))
return values
def calculate_average(values):
if not values:
return None
return sum(values) / len(values)
def reset_data(file_path):
if os.path.exists(file_path):
os.remove(file_path)
return True
return False
==== utility ====
import os
#
# VARIABLEN
#
DATADIR = "data"
FILENAME = "messwerte.txt"
#
# FUNKTIONEN
#
def get_file():
base_dir = os.path.dirname(os.path.dirname(__file__))
data_dir = os.path.join(base_dir, DATADIR)
os.makedirs(data_dir, exist_ok=True)
return os.path.join(data_dir, FILENAME)
def show_help():
print("\n====================== ANLEITUNG ======================")
print("(1) Wähle 'm', um eine Messung zu starten.")
print("(2) Drücke 'ENTER', um die Messung zu beginnen.")
print("(3) Warte, bis die Meldung 'JETZT!' erscheint.")
print("(4) Drücke dann sofort 'ENTER', um die Messung zu stoppen.")
print("")
print("Weitere Befehle:")
print("s - Statistik anzeigen")
print("r - Messwerte zurücksetzen")
print("h - Diese Anleitung anzeigen")
print("x - Programm beenden")
print("=========================================================")
def show_menu():
print("\n---------------------------------------------------------")
print("m - Messen")
print("s - Statistik anzeigen")
print("r - Reset")
print("h - Hilfe")
print("x - Beenden")
print("---------------------------------------------------------")
==== Hauptprogramm ====
#!/usr/bin/env python3
from core.logic import (
start_measurement,
save_value,
load_values,
calculate_average,
reset_data
)
from core.utility import get_file, show_menu, show_help
VERSION = "This is reflexio-advanced v1.0"
def main():
print(VERSION)
file_path = get_file()
while True:
show_menu()
choice = input("Eingabe: ").strip().lower()
if choice == "m":
reaction_time = start_measurement()
print("Status: Messung beendet")
print(f"Reaktionszeit: {reaction_time:.3f} Sekunden")
save_value(file_path, reaction_time)
values = load_values(file_path)
avg = calculate_average(values)
print(f"Anzahl Messwerte: {len(values)}")
print(f"Durchschnitt: {avg:.3f} Sekunden")
elif choice == "s":
values = load_values(file_path)
print()
if not values:
print("Es sind noch keine Messwerte vorhanden.")
else:
avg = calculate_average(values)
print(f"Anzahl Messwerte: {len(values)}")
print(f"Durchschnitt: {avg:.3f} Sekunden")
elif choice == "r":
print()
if reset_data(file_path):
print("Alle Messwerte wurden gelöscht.")
else:
print("Es sind keine gespeicherten Messwerte vorhanden.")
elif choice == "h":
show_help()
elif choice == "x":
print("Programm beendet.")
break
else:
print("Ungültige Eingabe. Mit 'h' Hilfe anzeigen.")
if __name__ == "__main__":
main()
++++