Programmierung mit Funktionen Klaus Becker 2015 2 Programmierung mit Funktionen 3 Teil 0 Vorbemerkungen zu Python 4 Entwicklungsgeschichte Die Sprache wurde Anfang der 1990er Jahre von Guido van Rossum am Centrum voor Wiskunde en Informatica (Zentrum für Mathematik und Informatik) in Amsterdam als Nachfolger für die Programmier-Lehrsprache ABC entwickelt, ursprünglich für das verteilte Betriebssystem Amoeba. Alle bisherigen Implementierungen der Sprache übersetzen den Text eines Python-Programms transparent in einen Zwischencode, der dann von einem Interpreter ausgeführt wird. Der Name geht nicht etwa (wie das Logo vermuten ließe) auf die gleichnamige Schlangengattung Pythons zurück, sondern bezog sich ursprünglich auf die englische Komikertruppe Monty Python. In der Dokumentation finden sich daher auch einige Anspielungen auf Sketche aus dem Flying Circus. Trotzdem etablierte sich die Assoziation zur Schlange, was sich u. a. in der Programmiersprache Cobra sowie dem Python Toolkit „Boa“ äußert. Quelle: Wikipedia 5 Python - Ziele Python wurde mit dem Ziel entworfen, möglichst einfach und übersichtlich zu sein. Dies soll durch zwei Maßnahmen erreicht werden: Zum einen kommt die Sprache mit relativ wenigen Schlüsselwörtern aus, zum anderen ist die Syntax reduziert und auf Übersichtlichkeit optimiert. Dies führt dazu, dass Python eine Sprache ist, in der man schnell, einfach und leicht programmieren kann. Sie ist daher besonders dort geeignet, wo Übersichtlichkeit und Lesbarkeit des Codes eine herausragende Rolle spielen – z. B. in der Teamarbeit, bei Beschäftigung mit dem Quelltext nach längeren Pausen oder bei Programmieranfängern. Durch die Möglichkeit, auch Programme anderer Sprachen als Modul einzubetten, werden viele Nischen in der Programmierung abgedeckt. Bei Bedarf lassen sich so beispielsweise zeitkritische Teile durch maschinennah in C programmierte Routinen ersetzen, oder Python kann als Skriptsprache eines anderen Programms dienen (Beispiele: OpenOffice.org, Blender, Maya, PyMOL, SPSS und GIMP). Quelle: Wikipedia 6 Python - Ziele Python ist eine Multiparadigmensprache. Das heißt, es zwingt den Programmierer nicht zu einem einzigen bestimmten Programmierparadigma, sondern erlaubt es, das für die jeweilige Aufgabe am besten geeignete Paradigma zu wählen. Objektorientierte und strukturierte Programmierung werden vollständig unterstützt, weiterhin gibt es Spracheigenschaften für funktionale und aspektorientierte Programmierung. Quelle: Wikipedia Quelle: http://kamelopedia.mormo.org/index.php/Eierlegende_Wollmilchsau Interne Abläufe 7 Der Quelltext eines Python Programms wird mit einem Texteditor geschrieben (z.B. Idle oder PyScripter). Compiler Interpreter Der Python-Compiler erzeugt einen (maschinenunabhängigen) Byte-Code. Der Compiler entscheidet selbst, ob der Byte-Code nur als Zwischenprodukt im Arbeitsspeicher erzeugt wird, oder ob er auch als .pyc-Datei gespeichert wird. Der Python-Interpreter führt den vom Compiler erzeugten Byte-Code aus. Derselbe Byte-Code kann auf verschiedenen Plattformen ausgeführt werden, sofern diese einen PythonInterpreter zur Verfügung stellen. 8 Gängige Python-Versionen http://www.python.org/download/ http://portablepython.com/releases/ 9 Entwicklungsumgebung Idle 10 Entwicklungsumgebung PyScripter 11 Literatur Johannes Ernesti, Peter Kaiser: Python 3. Das umfassende Handbuch. Galileo Computing 2009. (Preis: 40 €) Michael Weigend: Objektorientierte Programmierung mit Python. mitp 2008. (Preis: 40 €) Michael Weigend: Python Ge-Packt. mitp 2006. (Preis: 16 €) Thomas Theis: Einstieg in Python 3. Galileo Computing 2009. (Preis: 25 €) Gregor Lingl: Python für Kids. bhv 2008. (Preis: 20 €) P. Barry, D. Griffiths: Programmieren von Kopf bis Fuß. O´Reilly 2010 (Preis: 20 €) ... 12 Materialien Internet: Python Official Website http://www.python.org/ Python-Tutorium von Guido van Rossum: http://starship.python.net/crew/gherman/publications/tut-de/tut-de-21.pdf http://starship.python.net/crew/gherman/publications/tut-de/online/tut/ offenes eBook von von Peter Kaiser und Johannes Ernesti (Python 2.5): http://openbook.galileocomputing.de/python/?GalileoSession=10541258A3Vg6VBUX8A PythonWiki: http://wiki.python.de/ Python-Kurs von W.Spiegel: http://www.wspiegel.de/pykurs/pykurs.htm Python, Programmieren macht Spaß : http://www.thomas-guettler.de/vortraege/python/einfuehrung.html BICS: http://schule.de/bics/inf2/programmiersprachen/python/ Unterrichtsmaterialien von Klaus Merkert: http://www.hsg-kl.de/faecher/inf/python/index.php Unterrichtsmaterialien auf www.inf-schule.de 13 Teil 1 Miniprojekt „Baumhaus“ Datenverarbeitung mit Funktionen 14 Baumhaus Zielsetzung: Wenn man ein Baumhaus bauen möchte, sollte man vorher genau planen und vieles bedenken. Wir konzentrieren uns hier auf die Materialbeschaffung. Ziel ist es, eine Verarbeitungseinheit zu entwickeln, mit der man den Materialbedarf an Holz für unterschiedlich große Baumhäuser automatisiert bestimmen kann. 15 Ein einfaches Baumhausmodell Ziel ist es, den Bedarf an Brettern abzuschätzen, den man für die Außenwände und für das Dach des Hauses benötigt. Da das Haus auf einen Unterbau aufgesetzt werden soll, bleibt die Unterseite "offen" und wird bei der Materialberechnung nicht berücksichtigt. Zur Vereinfachung der Berechnungen werden Fenster- und Türöffnungen ebenfalls nicht berücksichtigt. Konkrete Berechnungen 16 Wir betrachten ein Haus mit den in der Abbildung vorgegebenen Maßen. Die erforderlichen Berechnungen führen wir mit Python aus. Python kann man im Ausführfenster wie einen Taschenrechner benutzen. Man gibt einen Berechnungsausdruck ein und lässt sich von Python das Ergebnis ausrechnen. Python-Dialog >>> 2.4 * 1.5 3.5999999999999996 >>> from math import sqrt >>> sqrt(0.9*0.9+0.4*0.4) 0.9848857801796105 Aufgabe: Bestimme die Gesamtoberfläche des Hauses (ohne den Boden). Zur Kontrolle: Die Gesamtoberfläche beträgt etwa 18m2. Entwickle eine Formel, mit der man die gesamte Oberfläche eines Hauses aus den gegebenen Größen berechnen kann. flaecheHaus(laenge, breite, hoeheHaus, hoeheDach) = 2*laenge*hoeheHaus + ... 17 Funktion als Verarbeitungseinheit Wenn man für viele unterschiedlich dimensionierte Baumhäuser den Materialbedarf berechnen möchte, ist es günstig, eine eigene Verarbeitungseinheit für diesen Zweck zu entwickeln. Das Verhalten der Verarbeitungseinheit lässt sich mit einem Black-Box-Diagramm verdeutlichen. Black-Box-Diagramm Funktionsdefinition 18 In Python lässt sich die konzipierte Verarbeitungseinheit als Funktion implementieren. Man öffnet ein neues Fenster und gibt den folgenden Quelltext dort ein. Achte auf die gezeigte Einrückung. Funktionsdefinition from math import sqrt def flaecheHaus(laenge, breite, hoeheHaus, hoeheDach): return 2*laenge*hoeheHaus + 2*breite*hoeheHaus + … Alles in eine Zeile from math import sqrt def flaecheHaus(laenge, breite, hoeheHaus, hoeheDach): Mit return 2*laenge*hoeheHaus + \ Zeilenumbrüchen 2*breite*hoeheHaus + \ 2*(breite*hoeheDach/2) + \ 2*laenge*sqrt((breite/2)*(breite/2)+hoeheDach*hoeheDach) Funktionsaufrufe 19 Das Programm (bzw. den Quelltext) muss man abspeichern und dann einmal ausführen, damit Python die neu definierte Funktion kennen lernt. Anschließend kann man die Funktion für Berechnungen im Ausführfenster verwenden. Programmfenster from math import sqrt def flaecheHaus(laenge, breite, hoeheHaus, hoeheDach): return 2*laenge*hoeheHaus + \ 2*breite*hoeheHaus + \ Funktionsdefinition 2*(breite*hoeheDach/2) + \ 2*laenge*sqrt((breite/2)*(breite/2)+hoeheDach*hoeheDach) >>> flaecheHaus(2.4, 1.8, 1.5, 0.4) 18.04745174486213 >>> flaecheHaus(2.8, 2.8, 2.0, 0.2) 30.879595949289328 Aufgabe: Funktionsaufrufe Ausführfenster Probiere das selbst aus. Bestimme analog die Oberfläche eines Hauses mit den folgenden Ausmaßen: Länge: 1.8m; Breite: 1.5m; Haushöhe: 1.2m; Dachhöhe: 0.3m. 20 Hilfsfunktionen Es ist oft schwierig, komplexe Berechnungsausdrücke zu entwickeln. Schwierig ist es zudem, komplexe Berechnungsausdrücke nachträglich zu durchschauen. In der Informatik nutzt man in solchen Situationen Strategien zur Reduzierung der Komplexität. Im vorliegenden Fall hilft es, Hilfsfunktionen einzuführen. def flaecheRechteck(a, b): return a*b Hilfsfunktionen 21 Verwendung von Hilfsfunktionen Bereits definierte Funktionen kann man benutzen, um neue Funktionen zu definieren def flaecheGiebel(breite, hoeheHaus, hoeheDach): return flaecheRechteck(breite, hoeheHaus) + \ flaecheDreieck(breite, hoeheDach) Schachtelung von Funktionen 22 Verwendung von Hilfsfunktionen Aufgabe (a) Entwickle analog Black-Box-Modellierungen und Funktionsdefinitionen für die Funktionen flaecheDach (für die gesamte Dachfläche) und flaecheSeitenwaende (für die Vorder- und Rückseite des Hauses). (b) Entwickle anschließend eine Black-Box-Modellierung und eine Funktionsdefinition für die Funktion flaecheHaus (für die gesamte Oberfläche des Hauses). Benutze hier die neu entwickelten Hilfsfunktionen. Bestimme mit dieser Funktion den Materialbedarf für die im letzten Abschnitt angegebenen Maße. 23 Weitere Berechnungsprobleme Siehe inf-schule 2.5.1.1.5 Variation des Hausmodells Materialbedarf für das Balkengerüst 24 Weitere Berechnungsprobleme Siehe inf-schule 2.5.1.1.5 Variation des Hausmodells 25 Teil 2 Fachkonzept – Funktion 26 Fachkonzept - Funktion Eine Funktion ist eine Verarbeitungseinheit, die übergebene Daten verarbeitet und den berechneten Funktionswert als Ergebnis zurückgibt. Als Beispiel betrachten wir eine Funktion, die aus den Daten eines Quaders (d.h. Länge, Breite und Höhe) die Mantelfläche bestimmt. 27 Fachkonzept - Funktion Eine Funktion hat einen Funktionsnamen. Im Beispiel hat die Funktion den Namen mantelQuaderflaeche. Den Funktionsnamen sollte man so wählen, dass das berechnete Ergebnis damit möglichst gut beschrieben wird. Zu verarbeitende Daten werden an Funktionsvariablen (man sagt auch Parameter) übergeben. Im Beispiel werden die drei Parameter laenge, breite und hoehe benutzt. Eine Funktion gibt das Verarbeitungsergebnis als Funktionswert zurück. 28 Fachkonzept - Funktion Die Verarbeitung wird über eine Funktionsdefinition (man sagt oft auch Funktionsdeklaration) festgelegt. Aktiviert wird eine Verarbeitung durch einen Funktionsaufruf. Funktionsname Funktionsvariablen /Parameter def mantelflaecheQuader(laenge, breite, hoehe): return (2*laenge + 2*breite) * hoehe Funktionsdefinition Aktuelle Daten >>> mantelflaecheQuader(3.0, 2.5, 0.8) 8.8 >>> mantelflaecheQuader(7.5, 4.2, 0.2) 4.68 Funktionsaufruf Funktionsdefinition in Python 29 Funktionskopf Schlüsselwort Funktionsname(Parameter) Doppelpunkt def mantelflaecheQuader(laenge, breite, hoehe): return (2*laenge + 2*breite) * hoehe Einrückung Funktionsrumpf Schlüsselwort Verarbeitungsvorschrift 30 Funktionsaufruf in Python Funktionsname(aktuelle Parameter) >>> mantelflaecheQuader(3.0, 2.5, 0.8) 8.8 >>> mantelflaecheQuader(7.5, 4.2, 0.2) 4.68 Funktionsaufruf Berechneter Funktionswert 31 Fachkonzept – teile und herrsche Als Beispiel betrachten wir die Berechnung der Oberfläche (ohne den Pyramidenboden) bei quadratischen Pyramiden. Problemzerlegung Berechnung der Oberfläche einer Pyramide Berechnung der Fläche eines Dreiecks Berechnung der Länge der Hypotenuse in einem rechtwinkligen Dreieck 32 Fachkonzept – teile und herrsche Berechnung der Oberfläche einer Pyramide Berechnung der Fläche eines Dreiecks Berechnung der Länge der Hypotenuse in einem rechtwinkligen Dreieck Problemzerlegung Problemlösung mit Hilfsfunktionen from math import sqrt def flaecheDreieck(g, h): return (g*h)/2 def laengeHypotenuse(a, b): return sqrt(a*a+b*b) def flaechePyramide(seite, hoehe): return 4*flaecheDreieck(seite, laengeHypotenuse(seite/2, hoehe)) 33 Fachkonzept – teile und herrsche Teile und herrsche ist eine Problemlösestrategie, bei der ein Problem immer weiter in Teilprobleme zerlegt wird, bis diese such einfach lösen lassen. Aus den Lösungen der Teilprobleme wird dann die Lösung des Gesamtproblems zusammengesetzt. Berechnung der Oberfläche einer Pyramide Berechnung der Fläche eines Dreiecks Berechnung der Länge der Hypotenuse in einem rechtwinkligen Dreieck Problemzerlegung Zusammensetzen von Funktionen def flaecheDreieck(g, h) def laengeHypotenuse(a, b) def flaechePyramide(seite, hoehe) 34 Übungen Siehe inf-schule 2.5.2.1.3 und 2.5.2.2.3 35 Teil 3 Miniprojekt „Räuber-Beute-Systeme“ Datenverwaltung mit Variablen 36 Räuber-Beute-Systeme Zielsetzung: Wir betrachten im Folgenden, wie sich eine Population aus Kaninchen und Füchse im Laufe der Zeit entwickelt. Es handelt sich hierbei um ein einfaches Räuber-Beute-System. Wir werden mit vereinfachenden Annahmen eine Modell für ein solches System entwickeln und hierauf basierend automatisierte Berechnungen zur Entwicklung eines sochen Systems erstellen. 37 Ein erstes Modell Wir betrachten zunächst den Fall, dass sich eine Population von Kaninchen und eine Population von Füchsen getrennt entwickeln. Wir gehen davon aus, dass die Kaninchen genügend Futter haben und sich daher - ohne bedrohende Feinde - ungehindert vermehren können. Bei der von der Kaninchenpopulation getrennt lebenden Fuchspopulation gehen wir davon aus, dass die Füchse nicht genügend Futter haben und dass sich die gesamte Population ständig verringert. Aufgabe: Wir gehen von einer Anfangspopulation von 1000 Kaninchen aus. In jedem Simulationsschritt soll die Population um 8% wachsen. Die Fuchspopulation soll zu Beginn aus 40 Füchsen bestehen. In jedem Simulationsschritt soll sich die Population um 20% des jeweiligen Bestands verringern. Ergänze die fehlenden Werte in der Tabelle. Akzeptiere Dezimalzahlen, auch wenn es in der Wirklichkeit keine Bruchteile von Kaninchen und Füchsen gibt. Ein erstes Modell 38 neueAnzahlKaninchen = anzahlKaninchen + zuwachsrateKaninchen*anzahlKaninchen 1080 = 1000 + 0.08 * 1000 Variable Aufgabe: Zur Verallgemeinerung der Berechnungen führen wir Variablen (als stellvertretende Namen für die zu verarbeitenden Daten) ein. Gib eine entsprechende Formel für die Entwicklung der Fuchspopulation an. 39 Ein verbessertes Modell Die Kaninchen und Füchse sollen jetzt gemeinsam in einem abgeschlossenen Areal leben. Für die Kaninchen bedeutet das, dass sie ab und zu auf Füchse treffen und dann (leider) gefressen werden. Wir berüchsichtigen dies, indem wir eine zusätzliche Abnahmerate vorsehen. Wir nehmen an, dass die Wahrscheinlichkeit, dass sich ein Kaninchen und ein Fuchs treffen, vom Produkt aus der Anzahl der Kaninchen und der Anzahl der Füchse abhängt. Die zusätzliche Abnahmerate beschreibt, in wieviel Prozent aller möglichen Treffen ein Kaninchen gefressen wird. Es ergibt sich folgende neue Berechnungsformel: neueAnzahlKaninchen = anzahlKaninchen + zuwachsrateKaninchen*anzahlKaninchen abnahmerateKaninchenFuchs*anzahlKaninchen*anzahlFuechse neueAnzahlFuechse = anzahlFuechse – abnahmerateFuechse*anzahlFuechse + zunahmerateFuchsKaninchen*anzahlFuechse*anzahlKaninchen 40 Ein verbessertes Modell neueAnzahlKaninchen = anzahlKaninchen + zuwachsrateKaninchen*anzahlKaninchen abnahmerateKaninchenFuchs*anzahlKaninchen*anzahlFuechse neueAnzahlFuechse = anzahlFuechse – abnahmerateFuechse*anzahlFuechse + zunahmerateFuchsKaninchen*anzahlFuechse*anzahlKaninchen Aufgabe: Bestimme mit den angegebenen Berechnungsformeln die fehlenden Werte in der Tabelle. Benutze folgende Daten: anzahlKaninchen = 1000 anzahlFuechse = 40 zuwachsrateKaninchen = 0.08 abnahmerateFuechse = 0.2 abnahmerateKaninchenFuchs = 0.002 zunahmerateFuchsKaninchen = 0.0004 Automatisierte Berechnungen 41 neueAnzahlKaninchen = anzahlKaninchen + zuwachsrateKaninchen*anzahlKaninchen 1080 = 1000 Aufgabe: Siehe inf-schule 2.5.1.2.3 Aufgabe 1. + 0.08 * 1000 Automatisierte Berechnungen 42 neueAnzahlKaninchen = anzahlKaninchen + zuwachsrateKaninchen*anzahlKaninchen 1080 = 1000 + def popKa5Schritte(anzKa, zKa): anzKa0 = anzKa anzKa1 = anzKa0 + zKa*anzKa0 anzKa2 = anzKa1 + zKa*anzKa1 anzKa3 = anzKa2 + zKa*anzKa2 anzKa4 = anzKa3 + zKa*anzKa3 anzKa5 = anzKa4 + zKa*anzKa4 return anzKa5 0.08 * 1000 Einführung neuer Variablen >>> popKa5Schritte(1000, 0.08) 1469.3280768 >>> popKa5Schritte(500, 0.2) 1244.1599999999999 Aufgabe: Siehe inf-schule 2.5.1.2.3 Aufgabe 2. Entwickle eine Funktion popKaFu5Schritte, mit der man die Entwicklung eines KaninchenFuchs-Systems simulieren kann. Teste die Funktion mit geeigneten Funktionsaufrufen. Automatisierte Berechnungen 43 neueAnzahlKaninchen = anzahlKaninchen + zuwachsrateKaninchen*anzahlKaninchen 1080 = 1000 Aufgabe: Siehe inf-schule 2.5.1.2.4 Aufgabe 1. + 0.08 * 1000 Automatisierte Berechnungen 44 neueAnzahlKaninchen = anzahlKaninchen + zuwachsrateKaninchen*anzahlKaninchen 1080 = 1000 def popKa5Schritte(anzKa, neueAnzKa = anzKa neueAnzKa = neueAnzKa neueAnzKa = neueAnzKa neueAnzKa = neueAnzKa neueAnzKa = neueAnzKa neueAnzKa = neueAnzKa return neueAnzKa + 0.08 * 1000 zKa): + + + + + zKa*neueAnzKa zKa*neueAnzKa zKa*neueAnzKa zKa*neueAnzKa zKa*neueAnzKa Überschreiben von Variablenwerten >>> popKa5Schritte(1000, 0.08) 1469.3280768 >>> popKa5Schritte(500, 0.2) 1244.1599999999999 Aufgabe: Entwickle analog eine Funktion popKaFu5Schritte, mit der man die Entwicklung eines Kaninchen-Fuchs-Systems simulieren kann. Teste die Funktion mit geeigneten Funktionsaufrufen. 45 Wiederholung von Berechnungen Die wiederholte Berechnung von Populationswerte erfolgte bisher, indem die zentrale Berechnungsformel (als Anweisung dargestellt) wiederholt im Quelltext aufgeführt wurde. def popKa5Schritte(anzKa, neueAnzKa = anzKa neueAnzKa = neueAnzKa neueAnzKa = neueAnzKa neueAnzKa = neueAnzKa neueAnzKa = neueAnzKa neueAnzKa = neueAnzKa return neueAnzKa zKa): + + + + + zKa*neueAnzKa zKa*neueAnzKa zKa*neueAnzKa zKa*neueAnzKa zKa*neueAnzKa def popKa5Schritte(anzKa, zKa): schritte = 5 zaehler = 0 neueAnzKa = anzKa while zaehler < schritte: neueAnzKa = neueAnzKa + zKa*neueAnzKa zaehler = zaehler + 1 return neueAnzKa Viele identische Anweisungen Wiederholungsanweisung 46 Wiederholung von Berechnungen Aufgaben: siehe inf-schule 2.5.1.2.5 47 Teil 4 Fachkonzept – Variable 48 Fachkonzept - Variable Variablen dienen in der Informatik dazu, Daten zu verwalten. Eine Variable ist ein Name, der (in der Regel) mit einem Datenobjekt verknüpft ist. listenpreis = 80.0 pMwSt = 19.0 mehrwertsteuer = (listenpreis / 100) * pMwSt endpreis = listenpreis + mehrwertsteuer Variablenzustand Als Wert einer Variablen wird das Datenobjekt angesehen, das von der Variablen verwaltet wird. Ein Variablenzustand beschreibt die aktuell vorliegenden Variablen mit den verwalteten Daten. 49 Fachkonzept - Zuweisung Eine Zuweisung ist eine Anweisung, die eine Variable mit einem neu berechneten Datenobjekt verknüpft. {} listenpreis = 80.0 {listenpreis -> 80.0} pMwSt = 19.0 {listenpreis -> 80.0; pMwSt -> 19.0} preis = listenpreis bindende Zuweisung {listenpreis -> 80.0; pMwSt -> 19.0; preis -> 80.0} preis = preis + (preis/100)*pMwSt überschreibende Zuweisung {listenpreis -> 80.0; pMwSt -> 19.0; preis -> 95.2} Aufbau einer Zuweisung: Eine Zuweisung besteht aus einer Variablen (der ein Wert zugewiesen wird) and einem Term (der den zuzuweisenden Wert festlegt). 50 Fachkonzept - Zuweisung Eine Zuweisung ist eine Anweisung, die eine Variable mit einem neu berechneten Datenobjekt verknüpft. Zustand - vorher {listenpreis -> 80.0; pMwSt -> 19.0; preis -> 80} preis = preis + (preis/100)*pMwSt preis -> 95.2 Auswertung {listenpreis -> 80.0; pMwSt -> 19.0; preis -> 95.2} Zustand - nachher Auswertung einer Zuweisung: Erst wird der Wert des Terms mit Hilfe des aktuellen Variablenzustands ermittelt. Dieser Wert wird dann der Variablen als neuer aktueller Wert zugewiesen. 51 Trace-Tabelle Eine Trace-Tabelle protokolliert die Veränderungen von Variablenzuständen, wenn mehrere Zuweisungen (bzw. sonstige Anweisungen) ausgeführt werden. Das folgende Beispiel zeigt eine solche Trace-Tabelle. 52 Variablenbezeichner Bei der Wahl der Variablenbezeichner (d.h. der Namen, die man den Variablen gibt) ist man recht flexibel: Verwendung von Buchstaben, Ziffern und dem Unterstrich; Unterscheidung zwischen Groß- und Kleinschreibung; keine Ziffern am Anfang; Umlaute sind erlaubt, machen aber gelegentlich Schwierigkeiten. Bei der Wahl der Variablenbezeichner sollte man sprechende Namen benutzen. Das sind Namen, die möglichst gut erklären, welche Daten mit den Variablen verwaltet werden. Funktionsvariablen 53 Funktionsvariablen werden benutzt, um die Daten zu verwalten, die zur Verarbeitung an eine Funktion übergeben werden. Solche Funktionsvariablen werden auch Parameter genannt. Funktionsvariable def zahlungsbetrag(listenpreis, pMwSt): mehrwertsteuer = (listenpreis / 100) * pMwSt endpreis = listenpreis + mehrwertsteuer return endpreis (lokale) Hilfsvariable Hilfsvariablen werden benutzt, um bei den Berechnungen anfallende Daten zwischenzuspeichern. Solche Variablen nennt man manchmal auch Speichervariablen. 54 Siehe inf-schule 2.5.2.4.4 Übungen 55 Teil 5 Miniprojekt „Verschlüsselung“ Verarbeitung von Zeichenketten Veschlüsselung 56 Zielsetzung: Ziel ist es, Textnachrichten automatisiert zu ver- und wieder entschlüsseln. Wir betrachten dabei einfache Verschlüsselungsverfahren wie das Verschiebeverfahren, das bereits von Caesar benutzt wurde. Verschiebeverfahren A B C D E F G H I J K L M N O P Q R S T U V W X Y Z D E F G H I J K L M N O P Q R S T U V W X Y Z A B C Quelltext: SALVEASTERIX Schlüssel: D Geheimtext: VDOYHDVWHULA Veschlüsselung 57 Aufgabe: Entschlüssele die in der Abbildung gezeigte Antwort von Asterix. Verschlüssele analog eine selbst gewählte Nachricht. Benutze jetz den Schlüssel 'H' (die Verschiebung erfolgt hier so, dass 'A' durch 'H' ersetzt wird). A B C D E F G H I J K L M N O P Q R S T U V W X Y Z D E F G H I J K L M N O P Q R S T U V W X Y Z A B C Quelltext: SALVEASTERIX Schlüssel: D Geheimtext: VDOYHDVWHULA Veschlüsselungsalgorithmus 58 ALGORITHMUS verschluesselterText: Übergabe: klartext, schluessel neuerText = '' für alle Zeichen c in klartext: ermittle mit dem schluessel das zu c verschobene Zeichen d füge d am Ende an die von neuerText verwaltete Zeichenkette an Rückgabe: neuerText A B C D E F G H I J K L M N O P Q R S T U V W X Y Z D E F G H I J K L M N O P Q R S T U V W X Y Z A B C Quelltext: SALVEASTERIX Schlüssel: D Geheimtext: VDOYHDVWHULA Zeichen und ihre Codierung 59 Zeichen werden intern im Rechner durch Bitfolgen codiert. Da man die Bitmuster auch als Zahlen deuten kann, lässt sich jedem Zeichen (aus einem vorgegebenen Zeichenvorrat) eine natürliche Zahl (aus einem passenden Zahlenbereich) zuordnen und umgekehrt. Dem Zeichen 'A' lässt sich beispielsweise nach dem ASCII-Code die Zahl 65 zuordnen. @ 0100 0000 40 64 P 0101 0000 50 80 A 0100 0001 41 65 Q 0101 0001 51 81 B 0100 0010 42 66 R 0101 0010 52 82 C 0100 0011 43 67 S 0101 0011 53 83 D 0100 0100 44 68 T 0101 0100 54 84 E 0100 0101 45 69 U 0101 0101 55 85 F 0100 0110 46 70 V 0101 0110 56 86 G 0100 0111 47 71 W 0101 0111 57 H 0100 1000 48 72 X 0101 1000 58 88 87 I 0100 1001 49 73 Y 0101 1001 59 89 J 0100 1010 4a 74 Z 0101 1010 5a 90 K 0100 1011 4b 75 [ 0101 1011 5b 91 L 0100 1100 4c 76 \ 0101 1100 5c 92 93 M 0100 1101 4d 77 ] 0101 1101 5d N 0100 1110 4e 78 ^ 0101 1110 5e O 0100 1111 4f 79 - 0101 1111 5f 94 95 Quelle: http://de.selfhtml.org/inter/zeichensaetze.htm Zeichen und ihre Codierung 60 Mit den (in Python) vordefinierten Funktionen ord und chr kann man Zeichen in Zahlen umwandeln und umgekehrt. @ 0100 0000 40 64 P 0101 0000 50 80 A 0100 0001 41 65 Q 0101 0001 51 81 B 0100 0010 42 66 R 0101 0010 52 82 C 0100 0011 43 67 S 0101 0011 53 83 D 0100 0100 44 68 T 0101 0100 54 84 E 0100 0101 45 69 U 0101 0101 55 85 F 0100 0110 46 70 V 0101 0110 56 86 G 0100 0111 47 71 W 0101 0111 57 H 0100 1000 48 72 X 0101 1000 58 88 87 I 0100 1001 49 73 Y 0101 1001 59 89 J 0100 1010 4a 74 Z 0101 1010 5a 90 K 0100 1011 4b 75 [ 0101 1011 5b 91 L 0100 1100 4c 76 \ 0101 1100 5c 92 93 M 0100 1101 4d 77 ] 0101 1101 5d N 0100 1110 4e 78 ^ 0101 1110 5e O 0100 1111 4f 79 - 0101 1111 5f 94 95 >>> ord('A') 65 >>> chr(65) 'A' 61 Bestimmung der Verschiebezahl Günstig ist es, wenn man zu einem Schlüsselbuchstaben die zugehörige Verschiebezahl ermitteln kann. Wir konzipieren hierfür eine geeignete Funktion. Aufgabe: Entwickle eine Funktionsdefinition für diese Funktion. Tipp: Benutze die vordefinierte Funktion ord. >>> ord('H') 72 62 Verschiebung von Buchstaben Ziel ist es, eine Funktion zum Verschlüsseln einzelner Zeichen (vorerst nur Großbuchstaben) mit einem vorgegebenen Schlüssel zu entwickeln. >>> >>> >>> >>> 7 >>> >>> 80 >>> >>> 87 >>> >>> 'W' zeichen = 'P' schluessel = 'H' verschiebung = verschiebezahl(schluessel) verschiebung Aufgabe: zahl = ord(zeichen) Führe selbst einen solchen Dialog zahl mit folgenden Ausgangsdaten: zeichen = 'M', schluessel = 'F'. neueZahl = zahl + verschiebung Führe ebenfalls einen Dialog mit neueZahl den Ausgangsdaten zeichen = 'U' und schluessel = 'M'. Welches neuesZeichen = chr(neueZahl) Problem tritt hier auf? Wie neuesZeichen könnte man es lösen? 63 Verschiebung von Buchstaben Ziel ist es, eine Funktion zum Verschlüsseln einzelner Zeichen (vorerst nur Großbuchstaben) mit einem vorgegebenen Schlüssel zu entwickeln. def verschluesseltesZeichen(zeichen, schluessel): verschiebung = verschiebezahl(schluessel) zahl = ord(zeichen) neueZahl = zahl + verschiebung if neueZahl > ord('Z'): neueZahl = neueZahl - 26 neuesZeichen = chr(neueZahl) return neuesZeichen Aufgabe: Teste diese Funktion. Beachte, dass du zusätzlich eine Implementierung der Funktion verschiebezahl benötigst. Am einfachsten speicherst du beide Funktionsdefinitionen in einer Datei ab. 64 Verschiebung von Buchstaben Aufgabe: Entwickle analog eine Funktion entschluesseltesZeichen. Erstelle erst ein Black-Box-Diagramm. Entwickle dann eine Funktionsdefinition. 65 Exkurs - Zeichenketten Eine Zeichenkette ist eine (evtl. leere) Folge von Zeichen (aus einer vorgegebenen Zeichenmenge), die zu einer Dateneinheit zusammengefasst ist. Der Datentyp Zeichenkette beschreibt die Menge der möglichen Zeichenkette zusammen mit den Operationen, die mit Zeichenketten vorgesehen sind. >>> z1 = 'Hallo' >>> z1 'Hallo' >>> z2 = "Hallo" >>> z2 'Hallo' >>> z = '' >>> z Darstellung von Zeichenketten >>> text = """Dieser Text geht ... über mehrere ... Zeilen.""" >>> text 'Dieser\nText geht\nüber mehrere\nZeilen.' >>> print(text) Dieser Text geht über mehrere Zeilen. 66 Exkurs - Zeichenketten Eine Zeichenkette ist ein sequentielles Datenobjekt, das aus einer Folge einzelner Zeichen besteht. Die Elemente eines solchen sequentiellen Datenobjekts sind der Reihe nach durchnummeriert. Die Nummerierung beginnt dabei mit 0. Die Nummer eines sequentiellen Datenobjekts wird auch Index genannt. >>> klartext = 'HALLO' >>> klartext[0] 'H' >>> klartext[1] 'A' >>> klartext[4] 'O' >>> klartext[5] Traceback (most recent call last): ... klartext[5] IndexError: string index out of range >>> len(klartext) 5 >>> klartext[len(klartext)-1] 'O' lesender Zugriff auf einzelne Zeichen beachte den Indexbereich Länge einer Zeichenkette 67 Exkurs - Zeichenketten Zeichenketten kann man über den Indexbereich, oder direkt über die einzelnen Zeichen durchlaufen. # klartext = ... i = 0 while i < len(klartext): # verarbeite klartext[i] i = i + 1 # klartext = ... for zeichen in klartext: # verarbeite zeichen Schleife über den Indexbereich for-Schleife für sequentielle Datenobjekte 68 Exkurs - Zeichenketten Eine Zeichenkette ist in Python ein nicht-veränderbares Datenobjekt. In Python ist nur ein lesender Zugriff auf einzelne Zeichen einer Zeichenkette möglich ist. Abändern kann man einzelne Zeichen einer Zeichenkette mit Hilfe von Zuweisungen nicht. Eine veränderte Zeichenkette erhält man nur, indem man eine neue Zeichenkette - z.B. mit dem Konkatenationsoperator - aufbaut. >>> klartext = 'HALLO' >>> klartext[1] 'A' >>> klartext[1] = 'E' TypeError: 'str' object does not support item assignment kein schreibender Zugriff erlaubt >>> klartext = 'HALLO' >>> klartextNeu = '' >>> klartextNeu = klartextNeu + klartext[0] >>> klartextNeu = klartextNeu + 'E' >>> klartextNeu 'HE' Zusammenfügen von Zeichenketten 69 Verschiebung von Zeichenketten Ziel ist es, eine Funktion zum Verschlüsseln von Texten nach dem Verschiebeverfahren zu implementieren. ALGORITHMUS verschluesselterText: Übergabe: klartext, schluessel neuerText = '' für alle Zeichen c in klartext: ermittle mit dem schluessel das zu c verschobene Zeichen d füge d am Ende an die von neuerText verwaltete Zeichenkette an Rückgabe: neuerText Aufgabe: Benutze die Informationen zu zeichenketten und die bereits implementierte Funktion verschluesseltesZeichen, um die Funktion verschluesselterText zu definieren. 70 Verschiebung von Zeichenketten Aufgabe: Entwickle analog eine Funktion zum Entschlüsseln von Texten, die mit dem Verschiebeverfahren verschlüsselt wurden. Aufgabe: Wir sind bisher davon ausgegangen, dass ein vorgegebener Text nur aus Großbuchstaben besteht. Einen beliebigen Text müsste man erst einmal in einen Text aus Großbuchstaben umwandeln, um das Verschlüsselungsverfahren anwenden zu können. Wir gehen dabei nach folgendem Verfahren vor: Alle Kleinbuchstaben werden in entsprechende Großbuchstaben umgewandelt. Alle Umlaute und das ß werden durch Kleinbuchstaben ersetzt. (z.B.: ä -> ae; ß -> ss). Alle Leerzeichen und alle Sonderzeichen werden weggelassen. Entwickle eine Funktion, die das leistet. Beschreibe zunächst das Verhalten mit einem BlackBox-Diagramm. Entwickle und teste dann eine Funktionsdefinition. Das Vigenère-Verfahren 71 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z K K L M N O P Q R S T U V W X Y Z A B C D E F G H I J A B C D E F G H I J K L M N O P Q R S T U V W X Y Z U U V W X Y Z A B C D E F G H I J K L M N O P Q R S T A B C D E F G H I J K L M N O P Q R S T U V W X Y Z H H I J K L M N O P Q R S T U V W X Y Z A B C D E F G Quelltext: VIG ENE RE Schlüssel: KUH Geheimtext: FCN OHL BY Das Vigenère-Verfahren 72 Schlüsselbuchstabe A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Klartextbuchstabe A B C D E F G H I J K L M N O P Q R S T U V W X Y Z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z B C D E F G H I J K L M N O P Q R S T U V W X Y Z A C D E F G H I J K L M N O P Q R S T U V W X Y Z A B D E F G H I J K L M N O P Q R S T U V W X Y Z A B C E F G H I J K L M N O P Q R S T U V W X Y Z A B C D F G H I J K L M N O P Q R S T U V W X Y Z A B C D E G H I J K L M N O P Q R S T U V W X Y Z A B C D E F H I J K L M N O P Q R S T U V W X Y Z A B C D E F G I J K L M N O P Q R S T U V W X Y Z A B C D E F G H J K L M N O P Q R S T U V W X Y Z A B C D E F G H I K L M N O P Q R S T U V W X Y Z A B C D E F G H I J L M N O P Q R S T U V W X Y Z A B C D E F G H I J K M N O P Q R S T U V W X Y Z A B C D E F G H I J K L N O P Q R S T U V W X Y Z A B C D E F G H I J K L M O P Q R S T U V W X Y Z A B C D E F G H I J K L M N P Q R S T U V W X Y Z A B C D E F G H I J K L M N O Q R S T U V W X Y Z A B C D E F G H I J K L M N O P R S T U V W X Y Z A B C D E F G H I J K L M N O P Q S T U V W X Y Z A B C D E F G H I J K L M N O P Q R T U V W X Y Z A B C D E F G H I J K L M N O P Q R S U V W X Y Z A B C D E F G H I J K L M N O P Q R S T V W X Y Z A B C D E F G H I J K L M N O P Q R S T U W X Y Z A B C D E F G H I J K L M N O P Q R S T U V X Y Z A B C D E F G H I J K L M N O P Q R S T U V W Y Z A B C D E F G H I J K L M N O P Q R S T U V W X Z A B C D E F G H I J K L M N O P Q R S T U V W X Y Schlüssel, Klartext K U H K U H K U V I G E N E R E F C N O H L B Y Geheimtext 73 Automatisierung d. Vigenère-Verfahrens Ziel ist es, eine Funktion zur Automatisierung des Vigenère-Verfahrens zu entwickeln. Es ist günstig, dabei die bereits implementierte Funktion verschluesseltesZeichen zu verwenden. >>> 'N' >>> 'Y' >>> 'U' >>> 'H' >>> 'P' ... verschluesseltesZeichen('G', 'H') verschluesseltesZeichen('E', 'U') verschluesseltesZeichen('H', 'N') verschluesseltesZeichen('E', 'D') verschluesseltesZeichen('I', 'H') 74 Automatisierung d. Vigenère-Verfahrens Ziel ist es, eine Funktion zur Automatisierung des Vigenère-Verfahrens zu entwickeln. >>> >>> 'N' >>> 'Y' >>> 'U' >>> 'H' >>> 'P' schluessel = 'HUND' verschluesseltesZeichen('G', schluessel[0]) verschluesseltesZeichen('E', schluessel[1]) verschluesseltesZeichen('H', schluessel[2]) verschluesseltesZeichen('E', schluessel[3]) verschluesseltesZeichen('I', schluessel[0]) Aufgabe: Entwickle eine Funktionsdefinition für die Funktion verschluesseltesZeichenVigenere. Teste ausführlich. 75 Teil 6 Fachkonzept – Datentyp 76 Fachkonzept - Datentyp Ein Datentyp beschreibt eine Menge von Datenobjekten, die alle die gleiche Struktur haben und mit denen die gleichen Operationen ausgeführt werden können. >>> 40.3 40.3 >>> type(40.3) <class 'float'> >>> round(40.3) 40 >>> type(40) <class 'int'> >>> str(40.3) + ' °C' '40.3 °C' >>> type('40.3 °C') <class 'str'> >>> (40.3, '°C') (40.3, '°C') >>> type((40.3, '°C')) <class 'tuple'> >>> 40.3 > 40 True >>> type(True) <class 'bool'> 40 30 20 10 0 77 Datentypen in Python >>> 2 2 Datentyp: ganze Zahl int >>> 2.0 2.0 Datentyp: Dezimalzahl float Datentyp: Wahrheitswert bool Datentyp: Zeichenkette string >>> ('Hans', 'Meier', 34) ('Hans', 'Meier', 34) Datentyp: Tupel tuple >>> [1, 2, 3, 4, 5] [1, 2, 3, 4, 5] Datentyp: Liste list ... ... >>> True True >>> 'Hallo!' 'Hallo!' >>> "Hallo!" 'Hallo!' Typumwandlungen in Python 78 Häufig benötigt man Operatoren, mit denen man aus einem Datenobjekt ein entsprechendes mit einem anderen Datentyp erzeugen kann. Der folgende Python-Dialog zeigt einige Möglichkeiten auf. >>> 3 >>> 3.0 >>> 3 >>> 3 >>> 3.0 >>> '3' int('3') float('3.0') int(3.0) int(3.5) float(3) str(3) >>> list('[1, 2, 3]') ['[', '1', ',', ' ', '2', ',', ' ', '3', ']'] >>> eval('[1, 2, 3]') [1, 2, 3] 79 Teil 7 Exkurs – Benutzerfreundliche Programme 80 Dialog im Ausführfenster Bisher wurden konkrete Berechnungen durch Funktionsaufrufe im Ausführfenster realisiert. Diese Vorgehensweise ist wenig benutzerfreundlich. Um Berechnungen durchzuführen muss der Benutzer den Namen der Funktion kennen (und richtig eintippen) und die Reihenfolge der zu bearbeitenden Daten kennen (und genau beachten). Programmfenster def verschiebezahl(zeichen): … def verschluesseltesZeichen(zeichen, schluessel): … def verschluesselterText(klartext, schluessel): … Ausführfenster >>> verschluesselterText('HALLO', 'G') 'NGRRU' >>> verschluesselterText('CAESAR', 'T') 'VTXLTK' 81 Ein interaktives Programm # Unterprogramme def verschiebezahl(zeichen): … def verschluesseltesZeichen(zeichen, schluessel): … def verschluesselterText(klartext, schluessel): … # Hauptprogramm # Eingabe print('Verwende nur die Großbuchstaben ABC...XYZ.') aktuellerSchluessel = input('Schlüssel: ') aktuellerKlartext = input('Klartext: ') # Verarbeitung aktuellerGeheimtext = verschluesselterText(aktuellerKlartext, aktuellerSchluessel) # Ausgabe print('Geheimtext:', aktuellerGeheimtext) Programmfenster 82 Ein interaktives Programm >>> Verwende nur die Großbuchstaben ABC...XYZ. Schlüssel: D Klartext: SALVESAESAR Geheimtext: VDOYHVDHVDU Ausführfenster Aufgabe: Speichere das Programm ab und führe es mit [Run][Run Module] aus. Im Ausführfenster wirst du zur Mitarbeit aufgefordert. Probiere das mehrmals mit verschiedenen Daten aus. Du musst das Programm hierzu jeweils wieder neu ausführen. 83 Fachkonzept - Programm Ein (Python-) Programm ist eine Folge von (Python-) Anweisungen und Kommentaren. Der Programmtext wird auch Quelltext genannt. # Unterprogramme def verschiebezahl(zeichen): … def verschluesseltesZeichen(zeichen,…): … def verschluesselterText(klartext, …): … # Hauptprogramm # Eingabe print('Verwende nur …') aktuellerSchluessel = input('Schlüssel: ') aktuellerKlartext = input('Klartext: ') # Verarbeitung aktuellerGeheimtext = … # Ausgabe print('Geheimtext:', aktuellerGeheimtext) Jede Anweisung wird im Quelltext in eine neue Zeile geschrieben. Die Verständlichkeit eines Programms wird durch sogenannte sprechende Bezeichner deutlich erhöht. Ein sprechende Bezeichner ist ein Name (z. B. für eine Variable), der die Bedeutung des bezeichneten Gegenstands möglichst gut wiedergibt. Kommentare dienen dazu, die Bedeutung von Programmteilen zu erläutern. Kommentare werden eigentlich nur für die Menschen ergänzt, die den Quelltext bearbeiten. Bei der Ausführung von Programmen werden sie ignoriert. 84 Fachkonzept - EVA-Prinzip Viele Programme lassen sich wie im folgenden Beispiel nach dem EVA-Prinzip strukturieren. EVA steht hier für Eingabe - Verarbeitung - Ausgabe. Auf einen Eingabeteil folgt ein Verarbeitungsteil und schließlich ein Ausgabeteil. Eingabe Verarbeitung Ausgabe # Eingabe ... … = input(…) # Verarbeitung ... … # Ausgabe print(…) ... Eingaben in Python: Der input-Operator gibt zunächst den Aufforderungstext aus, wartet dann, bis der Benutzer seine Eingabe mit der Return-Taste abgeschlossen hat und liefert diese Eingabe als Zeichenkette vom Typ str zurück. Ausgaben in Pythen: Die print-Anweisung gibt alle übergebenen Werte der Reihe nach (in einer Zeile) auf dem Bildschirm aus. 85 Laden und Speichern # Unterprogramme … def geladenerText(dateiname): datei = open(dateiname, 'r', encoding='iso-8859-1') text = datei.read() datei.close() return text def textSpeichern(dateiname, text): datei = open(dateiname, 'w', encoding='iso-8859-1') datei.write(text) datei.close() # Hauptprogramm # Eingabe print('Verwende nur die Großbuchstaben ABC...XYZ.') aktuellerSchluessel = input('Schlüssel: ') aktuellerDateinameLaden = input('Dateiname/Laden: ') aktuellerDateinamespeichern = input('Dateiname/Speichern: ') aktuellerKlartext = geladenerText(aktuellerDateinameLaden) # Verarbeitung aktuellerGeheimtext = verschluesselterText(aktuellerKlartext, aktuellerSchluessel) # Ausgabe textSpeichern(aktuellerDateinamespeichern, aktuellerGeheimtext) 86 Laden und Speichern >>> Verwende nur die Großbuchstaben ABC...XYZ. Schlüssel: D Dateiname/Laden: klartext.txt Dateiname/Speichern: geheimtext.txt Aufgabe: Teste das Programm. Beachte, dass sich die Datei, aus der der zu verschlüsselnde Text geladen werden soll, im selben Verzeichnis wie das Python-Programm befindet. 87 Fehlerbehandlung # Unterprogramme … # Hauptprogramm # Eingabe print('Verwende nur die Großbuchstaben ABC...XYZ.') aktuellerSchluessel = input('Schlüssel: ') aktuellerDateinameLaden = input('Dateiname/Laden: ') aktuellerDateinamespeichern = input('Dateiname/Speichern: ') # Funktionen benutzen try: aktuellerKlartext = geladenerText(aktuellerDateinameLaden) aktuellerGeheimtext = verschluesselterText(aktuellerKlartext, aktuellerSchluessel) textSpeichern(aktuellerDateinamespeichern, aktuellerGeheimtext) except: print('zu verarbeitende Datei nicht gefunden') Aufgabe: Erkundige dich, wie man mit einer try-except-Anweisung einen Laufzeitfehler verhindern kann, wenn die Datei zum Laden nicht gefunden wird. 88 Grafische Benutzeroberflächen Benutzerdialoge werden heutzutage über eine grafische Benutzeroberfläche geführt. Die Erstellung solcher Benutzeroberflächen ist etwas komplizierter und wird ausführlich erst in einer der nächsten Veranstaltungen behandelt.. 89 Teil 8 Miniprojekt „Primzahlen“ Ablaufmodellierung mit Kontrollstrukturen 90 Primzahlen Primzahlen sind natürliche Zahlen, die nur durch 1 und sich selbst ohne Rest teilbar sind. Beispiele: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, ... Zielsetzung: Primzahlen sind besondere Zahlen mit vielen interessanten Eigenschaften. Primzahlen sind auch sehr wichtig, da sie heutzutage bei der Sicherheit von Datenübertragungen im Internet eine zentrale Rolle spielen. In diesem Abschnitt sollen Bausteine zur Experimentieren mit Primzahlen entwickelt werden. Dabei spielt die Modellierung von komplexeren Berechnungsabläufen eine wichtige Rolle. 34608828249085121524296039576741331672262866890023854779048928344500622080983411446436437554415370753366448674763505018641470709332373970608376690404229 26578964799370976035846955231904548491005030414980981854028350715968356223294196805976228133454473972084926090485519277062605491179359038906079598116383 87214329942787636330953774381948448664711249676857988881722120330008214696844649561469971941269212843362064633138595375772004624420290646813260875582574 88470489384243989270236884978643063093004422939603370010546595386302009073043944482202559097406700597330570799507832963130938739885080198416258635194522 91304256293667985958749572103117374779641889506070194171750600193715243003236363193426579851623604745120908986470743078036229830703819344548649375664799 18042587755749738339033157350828910293923593527586171850199425548346718610745487724398807296062449119400666801128238240958164582617618617466040348020564 66823143718255492784779380991749580255263323326536457743894150848953969902818530057870876229329803338285735419228259022169602665532210834789602051686546 01146673798130605624748005507171825033373750226730734417851295073859433068434080269822896398656273259717537208729564907283028974977135833086795150871085 92167432185229188116706374484964985490944305412774440794079895398574694527721321665808857543604774088429133272929486968974961416149197398454328358943244 73601387609643750514699215032683744527071718684091832170948369396280061184593746143589068811190253101873595319156107319196071150598488070027088705842749 60520306319419116692210617615760936724194816062598903212798474808107532438263209391379644466570060139127836032300226743429519432560728066126011937871940 51514975551875492521342643946459638539649133096977765333294018221580031828892780723686021289827103066181151189641318936578454002968600124203913769646701 83983594954112484565597312460737798777092071706710824503707457220155015899591766244957768006802482976673920392995410164224776445671222149803657927708412 92555554281704557243084638998812996051922731398729120090206088206073376207589229947366640589742703581178687987569431507865442005560346962530939965395593 23104664300391464658054529650140400194238975526755347682486246319514314931881709059725887801118502811905590736777711874328140886786742863021082751492584 77101296451833651979717375170900505673645964696355331369819296000267389583289299126738345726980325998955997501176664201042888546085699446442834195232948 78748841059575019743878635311920421085580469246058253383296777194691145990192132498496881002118996828494133157316405630472548086892182344253819959038385 24127868408334796114199701017929783556536507553291382986542462253468272075036067407459569581273837487178259185274731649705820951813129055192427102805730 23145554793628499010509296055849712377978984921839997037415897674154830708629145484724536724572622450131479992681684310464449439022250504859250834761894 788889552527898400988196200014868575640233136509145628127191354858275083907891469979019426224883789463551 Primzahltest 91 Das Primzahltestproblem besteht darin, bei einer vorgegebenen natürlichen Zahl zu überprüfen, ob sie eine Primzahl ist. istPrimzahl natürliche Zahl True falls n eine Primzahl ist False falls n keine Primzahl ist n 92 Primzahltest Problem (Beispiel): Ist 551 eine Primzahl? Verfahren (Beispiel): Teile 551 der Reihe nach (von 2 bis ???) durch alle Zahlen und schaue jeweils, ob ein Rest bei der Division entsteht. Wenn das immer der Fall ist, dann handelt es sich um eine Primzahl. >>> 551 % 2 1 >>> 551 % 3 2 … Python als Taschenrechner Aufgabe: Führe den Primzahltest für n = 551 durch. Warum reicht es, wenn man bei dem skizzierten Verfahren der Reihe nach durch alle Zahlen von 2 bis √n teilt? Ein einfacher Primzahltestalgorithmus 93 ALGORITHMUS istPrimzahl: Übergabe: n prim = True k=2 SOLANGE k < n: WENN n % k == 0: prim = False k = k+1 Rückgabe: prim Aufgabe: Beschreibe den Verarbeitungsablauf mit einem Flussdiagramm. Welche Rolle spielt die Variable prim im gezeigten Algorithmus? Erkläre anhand eines Beispiels. Implementierung des Algorithmus 94 ALGORITHMUS istPrimzahl: Übergabe: n prim = True k=2 SOLANGE k < n: WENN n % k == 0: Ablaufbeschreibung mit Wahrheitswerten Wiederholung Fallunterscheidung prim = False k = k+1 Rückgabe: prim Rückgabe: Wahrheitswert Aufgabe: Informiere dich auf inf-schule 2.5.1.4.3, wie man die oben kommentierten Bausteine zur Ablaufmodellierung in Python implementiert. Entwickle mit diesem Wissen eine Funktionsdefinition für die Funktion istPrimzahl. Verbesserte Primzahltestalgorithmen 95 ALGORITHMUS istPrimzahl: Übergabe: n prim = True k=2 SOLANGE … : WENN n % k == 0: prim = False k = k+1 Rückgabe: prim Aufgabe: Wann kann man die Durchführung der Divisionen beenden? Wie könnte man das im Algorithmus berücksichtigen? 96 Verbesserte Primzahltestalgorithmen Die Funktion istPrimzahl verarbeitet eine Zahl vom Typ int (d.h. eine ganze Zahl) und liefert als Ergebnis einen Wert vom Typ bool (d.h. einen der beiden Wahrheitswerte True oder False) zurück. def istPrimzahl(n): prim = True k = 2 while k*k <= n and prim: if n % k == 0: prim = False k = k+1 return prim Aufgabe: Erläutere die gezeigte Funktionsdefinition. Teste die Funktion. Liefert sie immer korrekte Ergebnisse? 97 Teil 9 Fachkonzept - Kontrollstrukturen 98 Kontrollstrukturen Kontrollstrukturen sind Ablaufbausteine, die dazu dienen, die Reihenfolge der Abarbeitung von Anweisungen (eines Algorithmus / eines Programms) festzulegen. 99 Fachkonzept - Fallunterscheidung Eine Fallunterscheidung dient dazu, alternative Abläufe zu beschreiben. WENN [Bedingung]: [Anweisungssequenz] SONST: [Anweisungssequenz] zweiseitige Fallunterscheidung WENN [Bedingung]: [Anweisungssequenz] einseitige Fallunterscheidung 100 Fachkonzept - Fallunterscheidung Eine Fallunterscheidung dient dazu, alternative Abläufe zu beschreiben. zweiseitige Fallunterscheidung einseitige Fallunterscheidung Doppelpunkt if [Bedingung]: [Anweisungssequenz] else: [Anweisungssequenz] if x >= y: maximum = x minimum = y else: maximum = y minimum = x Schlüsselwort Einrückung if [Bedingung]: [Anweisungssequenz] maximum = x minimum = y if maximum < minimum: hilf = maximum maximum = minimum minimum = hilf 101 Fachkonzept - Wiederholung Eine Solange-Wiederholung besteht aus einer Bedingung und einer Anweisungssequenz. Solange die Bedingung erfüllt ist, wird die Anweisungssequenz ausgeführt. Aufbau SOLANGE [Bedingung]: [Anweisungssequenz] Struktogramm Python-Syntax Schlüsselwort Flussdiagramm Einrückung Doppelpunkt while [Bedingung]: [Anweisungssequenz] 102 Fachkonzept - Wahrheitswerte Wahrheitswerte (wahr and falsch bzw. True and False) treten bei der Auswertung von Bedingungen auf. Man benutzt sie oft auch zur Ablaufmodellierung. def istPrimzahl(n): prim = True k = 2 while k*k <= n and prim: if n % k == 0: prim = False k = k+1 return prim logische Variable zusammengesetzte Bedingung Mehr über Wahrheitswerte und ihre Verarbeitung erfährst du auf inf-schule 2.5.2.7. 103 Teil 10 Miniprojekt „Primzahlen“ Funktion als autonomer Baustein 104 Eine Funktion für Primzahltests Die Funktion istPrimzahl verarbeitet eine Zahl vom Typ int (d.h. eine ganze Zahl) und liefert als Ergebnis einen Wert vom Typ bool (d.h. einen der beiden Wahrheitswerte True oder False) zurück. def istPrimzahl(n): prim = True k = 2 while k*k <= n and prim: if n % k == 0: prim = False k = k+1 return prim 105 Eine Funktion für Primzahltests def istPrimzahl(n): prim = True k = 2 while k*k <= n and prim: if n % k == 0: prim = False k = k+1 return prim >>> istPrimzahl(13) True >>> istPrimzahl(15) ... >>> istPrimzahl(7) ... >>> istPrimzahl(551) ... >>> istPrimzahl(2) ... >>> istPrimzahl(1) ... >>> istPrimzahl(0) ... Funktionsdefinition Test mit Funktionsaufrufen 106 Verhaltensbeschreibung Es gibt verschiedene Möglichkeiten, das Verhalten einer Funktion (als Programmeinheit) zu beschreiben. Zum einem lässt sich das infomell mit einem Beschreibungstext tun. Daneben gibt es formalere Varianten, die bestimmte Formalismen zur exakten Beschreibung nutzen. Hierzu zählen u.a. das Black-Box-Diagramm und eine Beschreibung in Form von Testfällen. Black-Box-Diagramm >>> istPrimzahl(1) False >>> istPrimzahl(2) True >>> istPrimzahl(3) True >>> istPrimzahl(4) False >>> istPrimzahl(113) True >>> istPrimzahl(551) False Testfälle Docstring in Python 107 def istPrimzahl(n): … prim = True """ k = 2 Verhalten: while k*k <= n and prim: Übergabe: natürliche Zahl n if n % k == 0: Rückgabe: True, falls n … prim = False False, sonst k = k+1 Testfälle: return prim >>> istPrimzahl(13) True if __name__ == "__main__": >>> istPrimzahl(15) from doctest import testmod False testmod(verbose=True) >>> istPrimzahl(551) False >>> istPrimzahl(2) Automatisierte Überprüfung von True Testfällen >>> istPrimzahl(1) False Docstring mit Testfällen >>> istPrimzahl(0) False """ … 108 >>> Trying: istPrimzahl(13) Expecting: True ok Trying: istPrimzahl(15) Expecting: False ok Trying: istPrimzahl(551) Expecting: False ok Trying: istPrimzahl(2) Expecting: True ok … Docstring in Python … Trying: istPrimzahl(1) Expecting: False ******************************** File "...", line 19, in … Failed example: istPrimzahl(1) Expected: False Got: True Trying: istPrimzahl(0) … 1 items had failures: 2 of 7 in __main__.istPrimzahl 7 tests in 2 items. 5 passed and 2 failed. ***Test Failed*** 2 failures. 109 Docstring in Python Aufgabe: Probiere das selbst aus. Wie sind die Rückmeldungen von Python zu deuten? Verbessere die Funktionsdefinition so, dass alle Testfälle den Test bestehen. Tipp: Du musst zu Beginn eine zusätzliche Fallunterscheidung vorsehen. 110 Funktion als Baustein Eine gut getestete Funktionsdefinition kann man bei weiterführenden Problemlösungen als Baustein verwenden. Hier ein Beispiel, bei dem überprüft werden soll, ob ein Primzahlzwilling vorliegt. Baustein from primzahltest import istPrimzahl def istPrimzahlzwilling(n): if istPrimzahl(n): if istPrimzahl(n+2): ergebnis = True else: ergebnis = False else: ergebnis = False return ergebnis Verwendung des Bausteins 111 Funktion als Baustein Aufgabe: Entwickle eine Funktionsdefinition für eine Funktion naechstePrimzahl. Benutze die Funktion istPrimzahl als Baustein. Baustein 112 Der Primzahlsatz Die Anzahl der Primzahlen in einem Zahlenbereich lässt sich relativ genau abschätzen. Man verwendet hierzu den sogenannten Primzahlsatz. roter Graph: n -> Anzahl der Primzahlen kleiner oder gleich n grüner Graph: n -> n/ln(n) 113 Der Primzahlsatz Aufgabe: Entwickle eine Funktion, mit der man die Anzahl der Primzahlen ermitteln kann, die kleiner oder gleich einer übergebenen Zahl sind. Bestimme mit der entwickelten Funktion weitere Anzahlen und vergleiche mit der Abschätzung. >> from math import log >>> 100/log(100) 21.71472409516259 Manchmal hört man den Vorschlag, Primzahlen in einer Primzahldatenbank zu sammeln. In diese Datenbank sollten dann natürlich auch die Primzahlen kommen, die heutzutage beim Aufbau von Kryptosystemen benutzt werden. Moderne Kryptosysteme benutzen Primzahlen mit mehr als 300 Stellen. Schätze mit dem Primzahlsatz ab, wie viele Primzahlen es in diesem Bereich gibt. Betrachte hierzu den Bereich zwischen 21000 und 21001. Beurteile mit dem gewonnenen Ergebnis den oben gemachten Vorschlag. Zur Information: Die Anzahl der Atome im Universum liegt Schätzung zufolge im Bereich zwischen 1084 und 1089. 114 Goldbachs Vermutung Im Jahr 1742 teilte der Mathematiker Christian Goldbach seinem Kollegen Leonhard Euler eine interessante Beobachtung mit: Jede gerade Zahl, die größer als 2 ist, lässt sich als Summe von zwei Primzahlen darstellen. 4=2+2 6=3+3 8=3+5 10 = 3 + 7 = 5 + 5 12 = 5 + 7 14 = 3 + 11 = 7 + 7 16 = 3 + 13 = 5 + 11 … Viele Mathematiker haben seither versucht, Goldbachs Vermutung zu beweisen. Gelungen ist es bisher keinem. 115 Goldbachs Vermutung Aufgabe: Entwickle eine Funktion, mit der man die Anzahl der Zerlegungen einer geraden Zahl als Summe von zwei Primzahlen ermitteln kann. Bestimme mit der entwickelten Funktion weitere Anzahlen und beobachte, wie diese Anzahlen mit wachsendem n ebenfalls wachsen. Vergleiche auch mit den Ergebnissen in der folgenden Abbildung. Primfaktorzerlegung 116 Das Faktorisierungsproblem (kurz FACTORIZE) besteht darin, eine vorgegebene natürliche Zahl in ein Produkt aus Primfaktoren zu zerlegen. primfaktoren natürliche Zahl n L Liste der Primfaktoren von n primfaktoren 260 [2, 2, 5, 13] Primfaktorzerlegung 117 Aufgabe: Entwickle eine Funktion, mit der man die Primfaktoren einer natürlichen Zahl (größer 1) bestimmen kann. ALGORITHMUS primfaktoren: Übergabe: n faktoren = [] z=n SOLANGE z > 1: bestimme den kleinsten Primfaktor p von z faktoren = faktoren + [p] # füge p in die Liste faktoren ein z = z // p Rückgabe: faktoren