diff --git a/.gitignore b/.gitignore index ba74660..0a588ed 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ htmlcov/ nosetests.xml coverage.xml *,cover +.mypy_cache # Translations *.mo @@ -55,3 +56,9 @@ docs/_build/ # PyBuilder target/ + +# PyCharm +.idea/ + +# QML +*.qmlc diff --git a/Bugs.md b/Bugs.md new file mode 100644 index 0000000..1557ade --- /dev/null +++ b/Bugs.md @@ -0,0 +1,54 @@ +# Bugs und Fehlerbehebung +Grundsätzlich müssen drei Arten von Fehlern unterschieden werden: Syntaxfehler, Laufzeitfehler und Semantikfehler. + +## Syntaxfehler +Syntaxfehler sind ähnlich zu verstehen wie Rechtschreibfehler. Ein Befehl wurde nicht richtig geschrieben, eine Zeile nicht richtig eingerückt, eine Klammer nicht geschlossen. Syntaxfehler werden dabei gemeldet, bevor das eigentliche Programm ausgeführt wird. +``` + File "bug.py", line 1 + print("Test) + ^ +SyntaxError: EOL while scanning string literal + +``` +Hier wurde ein String nicht beendet. Die Fehlermeldung zeigt die Datei und die Zeile an, in der der Fehler aufgetreten ist, sowie eine Meldung um was für einen Fehler es sich handelt. + +``` + File "bug.py", line 2 + print("True") + ^ +IndentationError: expected an indented block +``` +Hier wurde die Einrückung weggelassen, was die Fehlermeldung auch mitteilt ("IndentationError"). Zudem wird wieder die Datei und die Zeile angezeigt. + + +Syntaxfehler sind einfach zu beheben, da sie schnell gefunden sind und die Fehlermeldung sehr genaue Auskunft darüber gibt, was passiert ist. Viele Texteditoren bieten zudem die Funktion an offene Klammern hervorzuheben, um schon die Entstehung von leicht vermeidbaren Fehlern zu vermeiden. + +## Laufzeitfehler +Laufzeitfehler finden, dem Namen nach, zur Laufzeit statt. Dabei gibt es verschiedene Fehlerquellen. Um die Fehlermeldung verständlicher zu machen werden die verschiedenen Arten von Laufzeitfehlern klassifiziert. + +### ValueError + +``` +Traceback (most recent call last): + File "", line 1, in + int("a") +ValueError: invalid literal for int() with base 10: 'a' + +``` + +Hier wurde versucht den String "a" in einen Integer umzuwandeln. Spezifischer in einen Integer mit der Basis 10, welches die Standardbasis für die Umwandlung in einen integer ist. Dies ist ein Beispiel für einen `ValueError`. Diese Fehler können auftreten, wenn zum Beispiel die Nutzereingaben nicht überprüft wurden. + +Laufzeitfehler zu finden ist weiterhin sehr einfach, da die Fehlermeldung sehr genau angibt, wo man zu suchen hat, weitaus schwieriger kann es allerdings werden einen Laufzeitfehler zu beheben, da dabei geklärt werden muss, ab wann das Programm den gewollten Zustand verlassen hat. + +### RecursionError + +``` +File "", line 2, in recursion + return recursion(x+1) +RecursionError: maximum recursion depth exceeded +``` + +Hier wurde eine rekursive Funktion ohne Abbruchbedingung gestartet. Die wird bis zu einem Limit an Durchläufen durchlaufen und wirft dann einen `RecursionError`. Dieser ist zweifelsohne ein sehr spezieller Fehler. + +## Semantikfehler +Semantikfehler sind von den beschriebenen drei Fehlerarten die weitaus schwierigste Kategorie, da sie vom Compiler oder Interpreter nicht angezeigt werden. Bei semantische Fehler, macht der Quellcode alles richtig, leider macht er nicht das, was er tun soll. Dabei sind Semantische Fehler sehr leicht zu erreichen. Wenn ich zum Beispiel in einer verschachtelten Schleife eine Anweisung in der falschen Einrückungsebene platziere, wird der Code wahrscheinlich noch funktionieren, allerdings nicht mehr das tun, was er soll. Somit ist beim Finden von Semantischen Fehlern sehr wichtig den erwarteten Output mit dem tatsächlichen Output zu vergleichen. \ No newline at end of file diff --git a/Glossar.md b/Glossar.md new file mode 100644 index 0000000..d83aa86 --- /dev/null +++ b/Glossar.md @@ -0,0 +1,85 @@ +# Glossar +## Level 0: +### Programmiersprache +Eine Programmiersprache ist eine formalisierte Form um den Computer in menschen-lesbarer Form Anweisungen zu geben. +Diese Anweisungen werden bei höheren Programmiersprachen vom Compiler bzw. Interpreter in eine vom Computer lesbare Sprache übersetzt. Höhere Programmiersprachen brauchen dieses Zwischenschritt um vom Computer verstanden werden zu können. +### Interpreter +Ein Interpreter ist ein Programm, dass Anweisungen in einer Programmiersprache entgegennimmt und verarbeitet. Dabei arbeitet es eine Anweisung nach der anderen ab. Somit wird der Programmcode zur Laufzeit geschrieben. Im Interpreter lassen sich sehr leicht kleine Codestücke testen. +### Compiler +Ein Compiler übersetzt Programmcode einer höheren **[Programmiersprache](#programmiersprache)** aus einer Datei in eine, vom Computer lesbare Sprache und speichert diese Übersetzung. Somit wird der Programmcode erst in eine Datei geschrieben, was es ermöglicht komplizierteren Code zu schreiben und zu schreiben. Da der Programmcode in Menschen lesbarer Form gespeichert wird, ist es möglich das Programm auf verschiedenen Systemen und an verschiedenen Zeitpunkten auszuführen. +## Level 1: +### Ausdruck +Ein Ausdruck (alternativ: Expression) ist ein grundlegender Bestandteil jedes Programms. Ein Ausdruck beschreibt einen **[Wert](#wert)** durch das Verknüpfen von **[Funktionen](#funktion)** oder **[Operatoren](#operator)** in Verbindung mit Werten oder **[Variablen](#variable)**. Ein Ausdruck ist dabei immer Bestandteil einer **[Anweisung](#anweisung)**. +### Anweisung +Eine Anweisung (alternativ: Befehl) ist grundlegender Bestandteil jedes Programms. Eine Anweisung kann verschiedene **[Ausdrücke(#ausdruck)** miteinander durch Funktionsaufrufe oder **[Operatoren](#operator)** verbinden aber auch einer **[Variable](#variable)** zuweisen. Im Allgemeinen enthält eine Codezeile eine Anweisung. +### Variable +Eine Variable zeigt auf einen **[Wert](#wert)**. Eine Variable hat immer einen Namen und einen Wert. In Python gibt es, anders als in anderen **[Programmiersprachen](#programmiersprache)**, keine Variablen mit einem festen **[Typ](#typ)**, das heißt einer Variable kann ein beliebiger Wert, mit einem beliebigen Typen zugeordnet werden. Die Arbeit mit Variablen erleichtert das Schreiben von Code stark. Zum Beispiel ist es möglich komplexe Anweisungen in kleinere Anweisungen zu kapseln und das Ergebnis dieser Anweisungen in Variablen zwischen zu speichern, dadurch wird der Code deutlich lesbarer. Durch geschickte Namenswahl einer Variable lässt sich die Lesbarkeit des Codes weiter erhöhen. +### Wert +Ein Wert ist sehr, abstrakt, ein Stück Information und in der Programmierung etwas sehr Grundlegendes. Ein Wert hat in Python immer einen **[Typen](#typ)**, der fest mit dem Wert verankert ist. So ist die `1` immer ein **[Integer](#integer)** und `True` immer ein **[Boolean](#boolean)**. +### Typ +Ein Typ wird definiert durch den Wertebereich und die möglichen Operationen, die mit **[Werten](#wert)** dieses Typs möglich sind. Zum Beispiel spezifiziert der Typ **[Integer](#integer)** den Wertebereich der ganzen Zahlen und als Operationen verschiedene Grundrechenarten und Vergleichsoperationen. Neben den Typen, die von Python mitgeliefert werden, ist es auch möglich eigene Typen zu definieren. Von veränderlichen oder dynamischen Typen spricht man, wenn das Ergebnis eines Ausdrucks den Wert verändert und keinen neuen Wert erzeugt. +### Schlüsselwort +Schlüsselwörter dienen der Strukturierung des Programmcodes und können daher nicht als Namen für **[Variablen](#variable)** verwendet werden. +### Integer +Ein Integer ist ein **[Typ](#typ)**, der von Python mitgeliefert wird und die ganzen Zahlen behandelt. Er bietet als Operationen die Grundrechenarten, sowie die Modulodivision, die Negation und Vergleichsoperationen. Ein Integer wird im Python-Code durch die entsprechende Zahl ausgedrückt. +### Float +### String +Ein String ist ein **[Typ](#typ)**, der von Python mitgeliefert wird. Die **[Werte](#wert)** eines Strings sind Zeichenketten beliebiger Länge. In Python wird ein String durch eine Zeichenkette in doppelten `""` oder einfach `''` Anführungszeichen ausgedrückt. +### Kommentare +Kommentare dienen der Lesbarkeit des Codes und werden von **[Compiler](#compiler)** und **[Interpreter](#interpreter)** ignoriert. Kommentare können benutzt werden um den Code zu erklären und sollten nicht nur wiederholen, was der Code tut. Im Grunde sollten Kommentare die Frage nach dem "Warum?" und nicht nach dem "Was?" klären. In Python kann ein Kommentar an einer beliebigen Stelle im Code mit einem "#" bis zu Ende der Zeile eingesetzt werden. +### Syntax +### Operator +## Level 2: +### Boolean +Der Boolean ist ein weiterer **[Typ](#typ)** der von Python mitgeliefert wird. Der Wertebereich besteht aus den beiden Werten `True` und `False`. Dabei erbt Boolean von **[Integer](#integer)**, besitzt also neben den Vergleichsoperatoren auch die Operatoren der Grundrechenarten, wobei `True` als 1 und `False` als 0 interpretiert wird. Der Ausdruck in der Definition einer **[if-Bedingung](#bedingung)** oder einer **[while-Schleife](#while-schleife)** wird in einen Boolean übersetzt und ausgewertet. +### Kommandostruktur +Eine Kommandostruktur ist essentieller Bestandteil von einer **[Programmiersprache](#programmiersprache)**, da für die meisten Programme Kommandostrukturen wie **[Bedingungen](#bedingung)** und **[Schleifen](#schleife)** zwingend benötigt werden. Eine weitere Kommandostruktur sind **[Funktionen](#funktion)**. +### Bedingung +Eine if-Bedingung nimmt einen Ausdruck entgegen, wandelt diesen in einen **[boolschen](#boolean)** **[Wert](#wert)** um und führt daraufhin einen Codeblock aus, wenn der Ausdruck `True`ergibt, andernfalls prüft es eventuelle weitere Bedingungen (`elif`) und oder oder führt den `else` Codeblock aus. Dabei sind alle weitere Bedingungen und der `else` Codeblock optional. Diese **[Kommandostruktur](#kommandostruktur)** dient dazu auf Eingaben oder andere Begebenheiten zu reagieren und ist für viele Algorithmen notwendig. +## Level 3: +### Element +Der Begriff Element wird häufig für **[Werte](#wert)** verwendet, die in einer **[Liste](#liste)** oder einem **[Tupel](#tupel)** gespeichert werden. +### Index +Als Index bezeichnet man die Position, bei 0 beginnend, eines **[Elementes](#element)** in einer **[Liste](#liste)** oder einem **[Tupel](#tupel)**. +### Liste +Eine Liste ist ein **[Typ](#typ)**, der in Python mitgeliefert wird. In einer Liste können beliebig viele **[Werten](#wert)** mit beliebigen **[Typen](#typ)** gespeichert werden. Dabei kann ein Wert beliebig häufig in der selben Liste auftreten. Ebenso können Werte verschiedenen Typs in der selben Liste gespeichert werden. Häufig werden die Werte in einer Liste als **[Elemente](#element)** bezeichnet. Auf die Elemente einer Liste wird über deren Position in der Liste (ihren **[Index](#index)**) zugegriffen. Die Zählung der Indexe beginnt dabei bei `0`, d.h. das erste Element einer Liste mit `n` Elementen hat den Index `0` und das letzte Element den Index `n-1`. Zu beachten ist, das im Gegensatz zu den Typen **[Integer](#integer)**, **[String](#string)**, **[Float](#float)** und **[Boolean](#boolean)** die Liste ein dynamischer Typ ist. +### Tupel +Ein Tupel ist ein **[Typ](#typ)**, der von Python mitgeliefert wird. Er besitzt ähnliche Eigenschaften wie der Typ **Liste**. Der markante Unterschied zwischen diesen +beiden Typen ist, dass ein Tupel unveränderlich ist, sowohl bezüglich der Anzahl der **[Elemente](#element)** als auch bezüglich der Elemente. Der Zugriff geschieht wie bei dervListe über den **[Index](#index)** eines Elements. +### Dictionary +Ein Dictionary ist ein **[Typ](#typ)**, der von Python mitgeliefert wird. Es ist ebenso wie die **[Liste](#liste)** oder das **[Tupel](#tupel)**, ein iterativer Typ. Im Gegensatz zu diesen beiden Typen wird auf ein **[Element](#element)**, dass in einem Dictionary gespeichert wird nicht über einen **[Index](#index)**, sondern über ein Schlüssel zugegriffen. +### Schleife +Eine Schleife ist eine **[Kommandostruktur](#kommandostruktur)** und dient dazu eine Folge von Anweisungen wiederholt auszuführen, bis eine **[Bedingung](#bedingung)** erreicht ist. Diese Bedingung nennt man Abbruchbedingung. In Python gibt es zwei Arten von Schleifen, die in ihren Möglichkeiten gleichwertig sind, sie unterscheiden sich jedoch in der **[Syntax](#syntax)**, und Handhabung. +#### while Schleife +Eine while-Schleife ist eine **[Schleife](#schleife)** , die einen **[boolschen](#boolean)** Ausdruck entgegennimmt, diesen auf Wahrheit prüft und dann einen Codeblock wiederholt ausführt. Nach jedem Durchlauf wird der boolsche Ausdruck erneut geprüft. Sollte der Ausdruck nicht mehr den **[Wert](#wert)** `True`ergeben, wird das Durchlaufen der Schleife beendet. +#### for Schleife +Eine for-Schleife ist eine **[Schleife](#schleife)** die ein iterierbares **[Objekt](#objekt)** durchläuft. Beispielsweise lassen sich somit **[Strings](#string)**, **[Listen](#liste)**, **[Tupel](#tupel)** oder **[Dictionaries](#dictionary)** durchlaufen. Durch die `range()` **[Funktion](#funktion)** lassen sich sehr Zählschleifen implementieren. +## Level 5: +### Funktion + +### Rekursion + +## Level 6: +### Objekt + +### Klasse + +### Modul + +### Instanz + +### Methode + +### Attribut + +## Level 7: +### Iterator + +### Generator + +### Decorator + +## Unsortiert: +### Exception + +### Syntaxfehler diff --git a/Level_00/README.md b/Level_00/README.md new file mode 100644 index 0000000..62787cb --- /dev/null +++ b/Level_00/README.md @@ -0,0 +1,46 @@ +# Level 0: + +## Was ist ein Programm? + + +## Was ist eine Programmiersprache? +Eine Programmiersprache dient dazu, dass ein Benutzer dem Computer durch Befehle (commands) und eine Syntax, +einen Algorithmus (oder Aufgaben) ausführen lässt. Die Programmiersprache ist eine formale Sprache, die +es ermöglicht, dem Computer präzise zu kommunizieren, was er tun soll. Allerdings ist die Programmiersprache +nur ein Zwischenschritt, da der Computer die Programmiersprache nochmal in eine Maschinensprache übersetzt. +Da diese Maschinensprache allerdings für den Menschen schwer lesbar ist, wird eine Programmiersprache wie +Python, Java, oder C benutzt. Es gibt viele verschiedene Programmiersprachen, die jedoch teilweise aufeinander +aufbauen, trotzdem kann man Programmiersprachen klassifizieren (Typisierung, Art der Ausführung, Syntax). + +Zum Beispiel ist Python eine stark und dynamisch typisierte Sprache, die sowohl im Interpreter als auch als Skript +ausgeführt werden kann. Sie wird meistens objektorientiert und imperativ verwendet. Was genau diese Attribute bedeuten, wird später noch erläutert. + +## Was genau ist Python? +Python ist eine Programmiersprache, die darauf ausgerichtet wurde, leicht benutzbar zu sein. Um dieses Ziel zu +erreichen verzichtet Python auf gewisse Eigenheiten anderer Programmiersprachen, die teilweise oft schwer +verständlich sind und häufig gerade Anfänger verwirren. Das bedeutet aber auch, dass andere Programmiersprachen +in bestimmten Anwendungsfällen besser geeignet sind als Python, weil sie zum Beispiel darauf optimiert wurden. +Trotzdem ist es sinnvoll, um eine Programmiersprache zu lernen, mit Python anzufangen, da zwischen den vielen +Programmiersprachen große Ähnlichkeiten bestehen. Sollte man eine weitere Sprache lernen wollen, versteht +man schon das Grundgerüst und muss sich nur noch mit der Syntax und den Eigenheiten der neuen Sprache +auseinandersetzen. + +## Wie programmiere ich mit Python? +Um mit Python zu programmieren, gibt es grundsätzlich zwei Möglichkeiten: +1. Ich führe in der Konsole den Interpreter aus und gebe live meine Befehle ein. +2. Ich schreibe mein Programm in eine Textdatei mit der Endung .py und rufe in der + Konsole die Textdatei mit Python auf. + + +Die erste Methode ist sehr praktisch, um kleine Codestücke zu testen oder kurze Programme auszuführen, ist jedoch +unkomfortabel, um große Programme zu schreiben, da das Programm nach Beenden des Interpreters weg ist. +Die zweite Methode ermöglicht es, große Programme zu schreiben, diese abzuspeichern und zu verteilen. Es ermöglicht +auch langfristiges Arbeiten an einem Programm. + +Für beide Methoden muss allerdings Python auf dem Betriebssystem installiert sein - sowohl auf dem Betriebssystem, +das ein Python-Programm ausführen soll, als auch das Betriebssystem, auf dem ein Python-Programm entwickelt wird. +Wir helfen euch gerne bei der Installation von Python auf Linux oder Windows. Solltet ihr Python selber +installieren, beachtet bitte, dass wir Python 3.x benutzen, da dies die aktuelle Version ist. + +## Wie führe ich Python aus? +siehe "Wie programmiere ich mit Python?" diff --git a/Level_01/Beispielcode/calculator01.py b/Level_01/Beispielcode/calculator01.py new file mode 100644 index 0000000..104d120 --- /dev/null +++ b/Level_01/Beispielcode/calculator01.py @@ -0,0 +1,47 @@ +""" +Das folgende Programm soll eine einfacher Taschenrechner sein. + +Das Programm nimmt zwei Zahlen entgegen und führt daraufhin einige Berechnungen +mit diesen durch. +""" + +# Für die Quadratwurzel benötigen wir die math Bibliothek +import math + +# Zuerst eine Willkommensnachricht +print() +print("Dies ist ein einfacher Taschenrechner.") +print() + +print("Bitte zwei Zahlen eingeben: ") +x = input("Erste Zahl: ") +y = input("Zweite Zahl: ") + +# Die beiden Eingaben werden in Zahlen umgewandelt, damit das Programm auch mit +# Fließkommazahlen arbeiten kann, wird der Typ float verwendet. +x = float(x) +y = float(y) + +# Jetzt werden einige Operationen mit den beiden Werten durchgeführt: +sum_xy = x + y # Summe +dif_xy = x - y # Differenz +dif_yx = y - x # Differenz +pro_xy = x * y # Produkt +quo_xy = x / y # Quotient +quo_yx = y / x # Quotient +mod_xy = x % y # Modulo Division +mod_yx = y % x # Modulo Division +x_sqrt = math.sqrt(x) # Quadratwurzel +y_sqrt = math.sqrt(y) # Quadratwurzel + +# Nun werden die Ergebnisse der Operationen ausgegeben: +print("x + y =", sum_xy) +print("x - y =", dif_xy) +print("y - x =", dif_yx) +print("x * y =", pro_xy) +print("x / y =", quo_xy) +print("y / x =", quo_yx) +print("x % y =", mod_xy) +print("y % x =", mod_yx) +print("sqrt(x) = ", x_sqrt) +print("sqrt(y) = ", y_sqrt) diff --git a/Level_01/Beispielcode/greeting.py b/Level_01/Beispielcode/greeting.py new file mode 100644 index 0000000..3734bc9 --- /dev/null +++ b/Level_01/Beispielcode/greeting.py @@ -0,0 +1,7 @@ +""" +Das Programm soll den Benutzer mit einer Grußnachricht begrüßen. +""" + +username = input("Please input your name: ") # Eingabe des Nutzernamens +greeting = "Hello " + username # Verarbeitung des Nutzernamens +print(greeting) # Ausgabe der Grußbotschaft \ No newline at end of file diff --git a/Level_01/Ein_Ausgabe.py b/Level_01/Ein_Ausgabe.py deleted file mode 100644 index 62b18fd..0000000 --- a/Level_01/Ein_Ausgabe.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 - -from getpass import getpass # hilfreich für Passwortabfragen - - -## Ausgabe - -print("Dieser Text wird ausgegeben.") - -# Man kann auch mehrere Dinge gleichzeitig ausgeben. -print(1, 2, "Apfel", "Birne") - -# Man kann auch Variablen ausgeben: -x = 5 -print(x) -text = "Hallo, Welt!" -print(text) -print(x, text) - - -## Eingabe - -print("Bitte etwas eingeben:") -eingabe = input() - -print("Die Eingabe war: ") -print(eingabe) - -# Das geht natürlich auch etwas kürzer: -eingabe = input("Bitte etwas eingeben: ") -print("Die Eingabe war:", eingabe) - -## Eingabe ohne die Eingabe anzuzeigen: -passwort = getpass() # Standardprompt: "Password: " -print("Eingabe:", passwort) - -passwort = getpass("Bitte Passwort eingeben: ") -print("Eingabe:", passwort) diff --git a/Level_01/Level_1.ipynb b/Level_01/Level_1.ipynb new file mode 100644 index 0000000..6436628 --- /dev/null +++ b/Level_01/Level_1.ipynb @@ -0,0 +1,903 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "# Level 1\n", + "\n", + "In diesem Level lernst du die Grundlagen des Programmierens kennen. Du lernst unter anderem:\n", + "\n", + "* einfache mathematischen Operationen durchzuführen\n", + "* die Datentypen `int`, `float` und `string` kennen\n", + "* was eine Variable ist und wie du Werte darin speicherst\n", + "* wie du mit Hilfe der `input()` Funktion Eingaben aus der Konsole entgegen nehmen kannst" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Ausgabe\n", + "\n", + "Die `print()`-Funktion hast du ja bereits in Level 0 kennengelernt. Diese Funktion gibt die ihr übergebenen Werte in der Konsole aus." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hallo Welt!\n" + ] + } + ], + "source": [ + "# Ein einfaches Beispiel für die Verwendung der print Funktion zum\n", + "# Ausgeben eines strings\n", + "print(\"Hallo Welt!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "foo bar\n", + "pi 3.14\n" + ] + } + ], + "source": [ + "# Du kannst auch mehrere Werte ausgeben lassen, wenn du diese mit Kommata trennst\n", + "print(\"foo\", \"bar\")\n", + "\n", + "# Dabei müssen die Werte nicht vom selben Typ sein\n", + "print(\"pi\", 3.14)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on built-in function print in module builtins:\n", + "\n", + "print(...)\n", + " print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n", + " \n", + " Prints the values to a stream, or to sys.stdout by default.\n", + " Optional keyword arguments:\n", + " file: a file-like object (stream); defaults to the current sys.stdout.\n", + " sep: string inserted between values, default a space.\n", + " end: string appended after the last value, default a newline.\n", + " flush: whether to forcibly flush the stream.\n", + "\n" + ] + } + ], + "source": [ + "# Mit der help() Funktion kannst du dir die Hilfe zu einem Objekt anzeigen lassen\n", + "help(print)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Die Hilfe der `print()` liefert dir wichtige Informationen darüber, wie du die Funktion benutzen kannst. So kannst du einen Separator angeben um zu definieren, welcher string zwischen zwei angegebenen Werten ausgegeben werden soll. Gibst du diesen Separator nicht explizit an handelt es sich um ein Leerzeichen. Ebenfalls kannst du einen end string angeben, der definiert, welcher string am Ende der Ausgabe ausgegeben werden soll. Gibst du diesen end string nicht explizit an, handelt es sich um `\\n`, das Steuerzeichen für einen Zeilenumbruch." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Apfel - Birne - Banane\n" + ] + } + ], + "source": [ + "# Ausgabe mit einem definiertem Separator\n", + "print(\"Apfel\", \"Birne\", \"Banane\", sep=\" - \")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "foo bar\n", + "test\n" + ] + } + ], + "source": [ + "# Ausgabe mit einem definiertem end-string:\n", + "print(\"foo\", \"bar\", end=\"\\n\")\n", + "print(\"test\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Ganze Zahlen und mathematische Operationen\n", + "\n", + "Bisher hast du gelernt, wie du Text in der Konsole ausgeben kannst. Im folgenden geht es darum, wie du Berechnungen durchführen kannst. Du kannst einfache mathematische Operationen direkt im Interpreter durchführen. Gib dafür im Interpreter einfach deinen Term ein." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "38" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "4 + 34" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Die obige Zeile besteht aus einem Literal (englisch: \"literal\") `4` einem Operator (englisch: operator) `+` und einem weiteren Literal `34`. Zusammen bilden diese beiden Literale und der Operator einen Ausdruck (englisch: expression). Ein Literal ist die direkte Darstellung eines Wertes. Ein Operator wird auf einen oder mehrere Werte angewandt und gibt dabei einen Wert zurück. Dabei ist es wichtig zu beachten, dass die Werte definieren wie der Operator mit ihnen umgeht und nicht umgekehrt.\n", + "\n", + "Die beiden Literale in dem obigen Beispiel haben den Typ `integer`. Der integer ist ein Datentyp, welcher die Menge der ganzen Zahlen implementiert. Ganze Zahlen sind sowohl positive als auch negative Zahlen ohne Nachkommastellen. Für diesen Datentyp sind verschiedene Operatoren definiert, diese bilden unter anderem die mathematischen Grundrechenarten ab." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n", + "-2\n", + "21\n", + "1\n", + "1\n", + "1.5\n", + "16\n" + ] + } + ], + "source": [ + "# Grundrechenarten\n", + "print(3 + 4) # Addition\n", + "print(4 - 6) # Subtraktion\n", + "print(3 * 7) # Multiplikation\n", + "print(3 // 2) # Ganzzahlige Division\n", + "print(3 % 2) # Division mit Rest\n", + "print(3 / 2) # Division\n", + "print(2 ** 4) # Potenz, alternativ pow(2, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8\n", + "2\n", + "4\n" + ] + } + ], + "source": [ + "# Bitweise Operationen\n", + "print(4 << 1) # Bitshift nach links, alternativ 4 * (2 ** 1)\n", + "print(4 >> 1) # Bitshift nach rechts, alternativ 4 // (2 ** 1)\n", + "print(5 ^ 1) # bitweises XOR" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Beachte, dass es drei Arten der Division gibt:\n", + "\n", + "* die ganzzahlige Division (`3 / 2`) liefert stets einen integer als Ergebnis, wobei nicht gerundet wird, weshalb es zu Genauigkeitsverlust kommen kann\n", + "* die module Division (`3 % 2`) liefert den Rest einer ganzzahligen Division\n", + "* die \"normale\" Division (`3 / 2`) liefert als Ergebnis eine Fließkommazahl (englisch: float)\n", + "\n", + "Im wiki findest du [weitergehende Informationen zum Thema \"Operatoren\"](https://github.com/pythonfoo/pythonfooLite/wiki/Operatoren)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Fließkommazahlen\n", + "\n", + "Wie bereits erwähnt implementiert der Datentyp `float` Fließkommazahlen. Diese können benutzt werden um mit Dezimalzahlen und ihren Nachkommastellen rechnen zu können. Ebenso wie für den `integer`-Datentyp sind auch für Fließkommazahlen die mathematischen Operatoren definiert. Du kannst auch in einem Ausdruck ganze Zahlen, Fließkommazahlen und verschiedene Operatoren miteinander verknüpfen. Dabei wird das Ergebnis des Ausdrucks stets eine Fließkommazahl sein, um Genauigkeitsverluste zu verhindern." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "rough estimate for circle area of radius 5\n", + "78.525\n" + ] + } + ], + "source": [ + "print(\"rough estimate for circle area of radius 5\")\n", + "print(5 ** 2 * 3.141)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Im Allgemeinen bietet jeder Datentyp eine Funktion um beliebige Werte (falls möglich) in diesen Typen umzuwandeln. So kann die `int()`-Funktion benutzt werden um einen Wert (beispielsweise eine Fließkommazahl) in eine ganze Zahl umzuwandeln. Bei dieser Umwandlung kommt es zu Genauigkeitsverlust. Die `float()`-Funktion hingegen kannst du dafür benutzen um aus einem beliebigen Wert eine Fließkommazahl zu machen." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5\n", + "2.0\n", + "15\n" + ] + } + ], + "source": [ + "print(int(3.5) + 2)\n", + "print(float(4) / 2)\n", + "print(int(\"5\") * int(\"3\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Variablen\n", + "> Readability counts. - Zen of Python\n", + "\n", + "Bisher musstest du die Ausdrücke, welche du ausgeben wolltest in einen Aufruf der `print()`-Funktion einbetten oder direkt im Interpreter eingeben. Gerade bei komplexeren Berechnungen ist dies nicht länger praktikabel. Die Benutzung von Variablen löst dieses und noch viele weitere Probleme.\n", + "\n", + "Eine Variable speichert einen Wert beliebigen Typs. Auf diesen gespeicherten Wert kann bei Bedarf beliebig oft zugegriffen werden. Die Variable dient insofern als Alias für den ihr gespeicherten Wert.\n", + "\n", + "Ein Wert wird in einer Variable gespeichert, indem man einem Variablennamen dieses Wert zuweist, weshalb dieser Vorgang \"Zuweisung\" genannt wird. Beachte bei der Vergabe von Variablennamen die Groß- und Kleinschreibung. Die Variable `pi` ist eine andere als die Variable `Pi` oder `PI`. Du solltest deine Variablennamen stets so wählen, dass aus dem Namen klar die beabsichtigte Bedeutung oder Rolle des gespeicherten Wertes hervorgeht. Zahlen können in Variablennamen benutzt werden, allerdings nicht als erstes Zeichen." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "radius = 5\n", + "pi = 3.14" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sobald du einen Wert in einer Variablen gespeichert hast, kannst du auf diesen Wert innerhalb von Ausdrücken mit Hilfe der Variable zugreifen." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "78.525\n" + ] + } + ], + "source": [ + "radius = 5\n", + "pi = 3.141\n", + "area = pi * radius ** 2\n", + "print(area)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## type()-Funktion\n", + "\n", + "Falls du dir mal nicht sicher bist, was dür einen Typ von Wert eine Variable enthält, kannst du dir den Typen eines beliebigen Wertes oder Ausdrucks mit Hilfe der `type()`-Funktion anzeigen lassen." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "\n", + "\n" + ] + } + ], + "source": [ + "# den Typen eines Wertes können wir mit type() bestimmt werden:\n", + "print(type(\"a\"))\n", + "print(type(2))\n", + "print(type(4.8))\n", + "\n", + "# auch die Typ-Bestimmung von Ausdrücken ist möglich\n", + "print(type(3.14 * 10))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Python besitzt eine streng dynamische Typisierung, das heißt:\n", + "\n", + "1. Eine Variable kann auf Werte verschiedenen Typs zeigen.\n", + "2. Jedes Objekt hat einen Typ.\n", + "\n", + "Sobald du einer Variable, der du bereits einen Wert zugewiesen hast, einen neuen Wert zuweist, wird der ursprüngliche Wert überschrieben und steht dir fortan nicht mehr zur Verfügung. Bei dieser Neuzuweisung ist es egal, welche Typen alter und neuer Wert haben." + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n" + ] + } + ], + "source": [ + "s = \"String\"\n", + "print(type(s))\n", + "s = 4\n", + "print(type(s))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Strings\n", + "Ein String ist eine Zeichenkette und wird repräsentiert Text.\n", + "Diese Zeichenkette kann ein Wort, einen Satz, einen Text, eine Seite oder sogar\n", + "ein Buch enthalten, wichtig ist nur, dass in einem String Text enthalten ist. Dies macht den String zu eine sehr\n", + "variablen Typen. Python unterstützt Unicode, was bedeutet, dass auch Sonderzeichen und Umlaute in einem String benutzt werden können.\n", + "\n", + "Ein String kann mit `\"\"` oder `''` definiert werden." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hallo Welt!\n", + "Programmieren mit Python.\n" + ] + } + ], + "source": [ + "hallo = 'Hallo Welt!'\n", + "text = \"Programmieren mit Python.\"\n", + "print(hallo, text, sep=\"\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Strings sind allerdings nicht auf eine Zeile begrenzt. Multiline strings werden durch dreifache Anführungszeichen definiert." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Dies ist ein\n", + "mehrzeiliger\n", + "String\n", + " mit Einrückung.\n", + "\n" + ] + } + ], + "source": [ + "multiline = \"\"\"\n", + "Dies ist ein\n", + "mehrzeiliger\n", + "String\n", + " mit Einrückung.\n", + "\"\"\"\n", + "print(multiline)" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "foobar\n" + ] + } + ], + "source": [ + "# Strings können wir miteinander \"addieren\", man spricht auch von konkatinieren\n", + "foo = \"foo\"\n", + "bar = \"bar\"\n", + "foobar = foo + bar\n", + "print(foobar)" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "########## foo ##########\n" + ] + } + ], + "source": [ + "# Strings können wir auch \"multiplizieren\":\n", + "print(10*\"#\" + \" foo \" + 10*\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Programmieren mit Python.\n", + "*************************\n", + "25\n" + ] + } + ], + "source": [ + "# len() liefert uns die Länge eines Objektes:\n", + "text = \"Programmieren mit Python.\"\n", + "length = len(text)\n", + "\n", + "print(text)\n", + "print(length*\"*\")\n", + "print(length)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "12\n" + ] + } + ], + "source": [ + "# mit der str() Funktion lassen sich Objekte in einen String umwandeln:\n", + "s = str(12)\n", + "print(s)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Die \"umgekehrte\" Operation geht natürlich auch, aber wir können nicht einfach jeden String in einen Integer umwandeln:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "invalid literal for int() with base 10: 'abcdef'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_287561/681081256.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"5\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"abcdef\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mValueError\u001b[0m: invalid literal for int() with base 10: 'abcdef'" + ] + } + ], + "source": [ + "x = int(\"5\")\n", + "int(\"abcdef\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Die Fehlermeldung weist uns auf ein ganz spannendes Feature hin: Wir können die Basis angeben.\n", + "Bisher haben wir (standardmäßig) Dezimalzahlen verwendet (Basis 10). Wir können aber z.B. auch Hexadezimalzahlen (Basis 16) verwenden:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "11259375\n", + "0xabcdef\n" + ] + } + ], + "source": [ + "x = int(\"abcdef\", 16)\n", + "print(x)\n", + "print(hex(x))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Analog zu `hex` existieren auch `bin` (binär, Basis 2) und `oct` (oktal, Basis 8).\n", + "Diese drei sind so häufig, dass sich auch Literale damit formulieren lassen (`0x` für hexadezimal, `0b` für binär, `0o` für oktal):" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0o777\n", + "0b1011\n", + "0xc0ffee\n" + ] + } + ], + "source": [ + "print(oct(0o777))\n", + "print(bin(0b1011))\n", + "print(hex(0xc0ffee))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wir können mit Strings noch viel mehr tun. Ein paar Funktionen zeigen wir hier, mehr folgen später:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "LOREM IPSUM\n", + "lorem ipsum\n", + "Lorem ipsum\n" + ] + } + ], + "source": [ + "t = \"loREm ipSUm\"\n", + "\n", + "# Alle Buchstaben groß:\n", + "print(t.upper())\n", + "\n", + "# Alle Buchstaben klein:\n", + "print(t.lower())\n", + "\n", + "# Den ersten Buchstaben groß:\n", + "print(t.capitalize())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Eingabe\n", + "Die `input()`Funktion wird benutzt um Eingaben über die Standardeingabe zu erhalten. Dabei liefert die `input()`-Funktion immer einen String zurück.\n", + "\n", + "Da die Eingabe fast immer weiterverarbeitet werden soll, bietet es sich an, die Rückgabe in einer Variable zu speichern." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Bitte etwas eingeben: foo\n", + "foo\n", + "\n" + ] + } + ], + "source": [ + "eingabe = input(\"Bitte etwas eingeben: \")\n", + "print(eingabe)\n", + "print(type(eingabe))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wenn wir statt `input()` `getpass()` verwenden, dann verhält es sich quasi genau so, nur die Eingabe wird nicht angezeigt:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "geheim\n" + ] + } + ], + "source": [ + "from getpass import getpass\n", + "password = getpass(\"Passwort: \")\n", + "print(password)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Schlüsselwörter\n", + "Einige Begriffe sind integrale Bestandteile von Python und können daher nicht als Variablenname benutzt werden. Diese Schlüsselwörter variieren von Version zu Version. Eine Liste aller Schlüsselwörter können wir uns anzeigen lassen:" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']\n" + ] + } + ], + "source": [ + "import keyword\n", + "print(keyword.kwlist)" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "can't assign to keyword (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m True = 0 # Anzahl an Versuchen\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m can't assign to keyword\n" + ] + } + ], + "source": [ + "True = 0 # Anzahl an Versuchen" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Kommentare\n", + "> If the implementation is hard to explain, it's a bad idea - Zen of Python\n", + "\n", + "Kommentare dienen dazu den Quellcode für sich und andere lesbarer und verständlich zu machen. Kommentare können in Python mittels einer Raute (`#`) eingefügt werden. Dabei kann eine ganze Zeile zum Kommentar werden, oder ein Kommentar hinter einem Befehl eingefügt werden, dabei sollten wir vor der Raute zwei Leerzeichen Platz lassen.
\n", + "Dabei sollten wir beachten, dass ein Kommentar nie beschreiben sollte, __was__ der Code macht, sondern __warum__ der Code etwas macht." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "12\n" + ] + } + ], + "source": [ + "# Berechnen der Summe zweier Zahlen\n", + "sum1 = 5 # erster Summand\n", + "sum2 = 7 # zweiter Summand\n", + "print(sum1 + sum2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Zen of Python\n", + "Der \"Zen of Python\" bietet einige Leitlinien, an denen sich Python als Sprache orientiert und an denen wir uns auch beim Programmieren mit Python orientieren können. In bisherigen Abschnitten wurden Teile bereits zitiert, unten sind einmal alle Punkte aufgelistet." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The Zen of Python, by Tim Peters\n", + "\n", + "Beautiful is better than ugly.\n", + "Explicit is better than implicit.\n", + "Simple is better than complex.\n", + "Complex is better than complicated.\n", + "Flat is better than nested.\n", + "Sparse is better than dense.\n", + "Readability counts.\n", + "Special cases aren't special enough to break the rules.\n", + "Although practicality beats purity.\n", + "Errors should never pass silently.\n", + "Unless explicitly silenced.\n", + "In the face of ambiguity, refuse the temptation to guess.\n", + "There should be one-- and preferably only one --obvious way to do it.\n", + "Although that way may not be obvious at first unless you're Dutch.\n", + "Now is better than never.\n", + "Although never is often better than *right* now.\n", + "If the implementation is hard to explain, it's a bad idea.\n", + "If the implementation is easy to explain, it may be a good idea.\n", + "Namespaces are one honking great idea -- let's do more of those!\n" + ] + } + ], + "source": [ + "import this" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10.6 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + }, + "vscode": { + "interpreter": { + "hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git "a/Level_01/L\303\266sungen/addierer.py" "b/Level_01/L\303\266sungen/addierer.py" new file mode 100755 index 0000000..d902178 --- /dev/null +++ "b/Level_01/L\303\266sungen/addierer.py" @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 + +# Dies ist eine Beispiellösung für die Aufgabe 1 aus Level 1: + +# 1. Schreibe ein Programm, das die Zahlen 23 und 42 addiert: + +print(23 + 42) # Erfüllt die Anforderung komplett. + + +# 2. Ändere das Programm so ab, dass die Zahlen in zwei Variablen gespeichert werden: + +a = 23 +b = 42 +# Alternativ: a, b = 23, 42 +print(a + b) + + +# 3. Ändere dein Programm so ab, dass die Zahlen interaktiv eingegeben werden können: + +inp_a = input("Bitte geben Sie den ersten Summanden ein: ") # type: str +inp_b = input("Bitte geben Sie den zweiten Summanden ein: ") +# Da input() immer einen String zurückgibt muss dieser in einen Integer umgewandelt werden, +# dabei entsteht eine Fehlerquelle, da ein Fehler auftritt, wenn der Benutzer keine gültige +# Zahl eingibt. +a = int(inp_a) +b = int(inp_b) + +print(a + b) diff --git "a/Level_01/L\303\266sungen/print_string.py" "b/Level_01/L\303\266sungen/print_string.py" new file mode 100755 index 0000000..bdda207 --- /dev/null +++ "b/Level_01/L\303\266sungen/print_string.py" @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 + +# Dies ist eine Beispiellösung für die Aufgabe 2 aus Level 1: + +# 1. Schreibe ein Programm, das den String "foo" ausgibt +print("foo") # Sehr ähnlich dem "hello world" Code + + +# 2. Ändere das Programm so ab, dass es den String "foo" 5 mal ausgibt: +print("foo") +print("foo") +print("foo") +print("foo") +print("foo") + + +# 3. Ändere das Programm so ab, dass der String 5 mal in der selben Zeile ausgegeben wird. +print(5*"foo") + + +# 4. Ändere das Programm so ab, dass interaktiv eingegeben werden kann, +# welcher String 5 mal in der selben Zeile ausgegeben werden soll. +string = input("Welcher String soll ausgegeben werden? ") +print(5*string) + + +# 5. Ändere das Programm so ab, dass interaktiv eingegeben werden kann, +# wie oft der angegebene String ausgegeben werden soll. +string = input("Welcher String soll ausgegeben werden? ") +wiederholung = input("Wie oft soll '" + string + "' ausgegeben werden? ") +# Hier wird in dem Aufruf von input() ein String zusammen gebaut + +# Wie in Aufgabe 1 muss auch hier der String in einen Integer umgewandelt werden +wiederholung = int(wiederholung) + +print(wiederholung*string) diff --git a/Level_01/README.md b/Level_01/README.md new file mode 100644 index 0000000..dc1ce36 --- /dev/null +++ b/Level_01/README.md @@ -0,0 +1,30 @@ +# Level 1 + +In Level 0 hast du Python installiert und mit `hello_world.py` dein erstes Python-Programm geschrieben. +In Level 1 geht es unter anderem darum zwei grundlegende Funktionen für die Ein- und Ausgabe kennenzulernen, die Funktionen `input()` und `print()`. +Ebenso wirst du in diesem Level die einfachen Datentypen `int`, `float` und `str` kennenlernen. +Du wirst lernen Werte in Variablen zu speichern und auf diese Variablen später zuzugreifen. + +Um mit diesem Level zu starten, navigiere zur [Level1.ipynb](https://github.com/pythonfoo/pythonfooLite/blob/master/Level_01/Level_1.ipynb) Datei. + +## Aufgaben + +Um deine erworbenen Kenntnisse anwenden und testen zu können, haben wir für dieses Level ein paar Aufgaben erstellt. Die Aufgabenstellungen sind dabei an den Inhalt des Levels angepasst. Falls du dennoch Probleme oder Fragen zu diesem Level oder den Aufgaben hast, kannst du dich gerne an uns wenden. Jede Aufgabe hat eine eindeutige Nummer zur Identifizierung und meistens auch einen Namen. + +### 1.1 addierer.py + +In dieser Aufgabe geht es darum ein Programm zu schreiben, welches zwei ganze Zahlen addiert. Diese Aufgabe ist dabei in Teilaufgaben gegliedert, wobei folgende Teilaufgaben die bestehenden Anforderungen erweitern. In der ersten Aufgabe erstellst du also einen Prototypen, dessen Funktionalität du Schritt für Schritt erweiterst. + +1. Schreibe ein Programm, das die Zahlen 23 und 42 addiert und das Ergebnis ausgibt. +2. Ändere dein Programm so ab, dass die Zahlen in zwei Variablen gespeichert werden. +3. Ändere dein Programm so ab, dass die Zahlen interaktiv eingegeben werden können. + +### 1.2 print_string.py + +Diese Aufgabe beschäftigt sich mit der `print()` Funktion. Wie in Aufgabe **1.1** wird auch hier mit jeder Teilaufgabe das bestehende Programm erweitert. + +1. Schreibe ein Programm, das den String "foo" ausgibt +2. Ändere das Programm so ab, dass der String "foo" 5 mal ausgegeben wird. +3. Ändere das Programm so ab, dass der String 5 mal in der selben Zeile ausgegeben wird. +4. Ändere das Programm so ab, dass interaktiv eingegeben werden kann, welcher String 5 mal in der selben Zeile ausgegeben werden soll. +5. Ändere das Programm so ab, dass interaktiv eingegeben werden kann, wie oft der angegebene String ausgegeben werden soll. diff --git a/Level_01/buggy01.py b/Level_01/buggy01.py new file mode 100644 index 0000000..31efddf --- /dev/null +++ b/Level_01/buggy01.py @@ -0,0 +1,15 @@ +# In dieses Programm sind verschiedene Fehler eingebaut, +# die Aufgabe besteht darin die Fehler zu finden und zu beheben. + +a = inpu("Bitte eine Zahl eingeben: ") +b = input("Bitte eine weitere Zahl eingeben: ) + +summe = a + b +differenz = abs(a - b) +produkt = a * b +quotient = a / b + + print("Summe: " + summe) +print("Differenz: " + diferenz) +print("Produkt: " + produkt) +print("Quotient: " + Quotient) diff --git a/Level_01/integer.py b/Level_01/integer.py deleted file mode 100644 index 7983406..0000000 --- a/Level_01/integer.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python3 - -x = 5 -z = -3 -basis = 2 -exponent = 5 - -# Daten andere Typen in Integer umwandeln -# Achtung: Dies kann fehlschlagen! -y = int("6") - -# Operatoren auf Integer anwenden: -# (für mehr Informationen siehe die Wiki-Seite zu Operatoren) -summe = x + y -produkt = x * z -quotient = 9 / 3 -differenz = x - z -potenz = pow(basis, exponent) # Oder: basis ** exponent, Falsch ist basis ^ exponent diff --git a/Level_01/strings.py b/Level_01/strings.py deleted file mode 100644 index 6c7f72b..0000000 --- a/Level_01/strings.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 - -# zur Bedeutung von `print` siehe Ein_Ausgabe.py - -ein = "Dies ist ein einzeiliger String." -print(ein) - -mehr = """ -Dies ist ein mehrzeiliger String. - - Leerzeilen, Zeilenumbrüche und Einrückung - werden mit in den String übernommen. -""" - -print(mehr) - -f = "foo" -b = "bar" - -# Operatoren auf Strings anwenden: -# (für mehr Informationen siehe die Wiki-Seite zu Operatoren) -print(f + b) -print(5 * f) -print(5 + (f + " ")) - -# Daten anderer Typen in Strings umwandeln: -s = str(5) -print(s) \ No newline at end of file diff --git a/Level_02/Beispielcode/calculator02_if.py b/Level_02/Beispielcode/calculator02_if.py new file mode 100644 index 0000000..de9abf0 --- /dev/null +++ b/Level_02/Beispielcode/calculator02_if.py @@ -0,0 +1,77 @@ +""" +Das folgende Programm ist ein einfacher Taschenrechner. + +Nach dem Eingeben zweier Zahlen kann eine Operation ausgewählt werden. +""" + +# Für die Berechnung der Quadratwurzel wird die math Bibliothek benötigt, +# des Weiteren wird zum vorzeitigen Beenden die sys Bibliothek benötigt. +import math +import sys + +# Zuerst eine Willkommensnachricht +print() +print("Dies ist ein einfacher Taschenrechner.") +print() + +print("Bitte zwei Zahlen eingeben: ") +x = input("Erste Zahl: ") +y = input("Zweite Zahl: ") + +# Die beiden Eingaben werden in Zahlen umgewandelt, damit das Programm auch mit +# Fließkommazahlen arbeiten kann, wird der Typ float verwendet. +x = float(x) +y = float(y) + +# Zuerst wird ein kleines Menü angezeigt: +print("0: Betrag") +print("1: Summe") +print("2: Produkt") +print("3: Differenz") +print("4: Quotient") +print("5: Modulo Division") +print("6: Quadratwurzel") +print("7: Potenz") +print("q: Beenden") + +# Nun wird nach der Auswahl gefragt +choice = input("Bitte eine Operation aussuchen: ") + +if choice == "0": + print("|x| =", abs(x)) # Betrag von x + print("|y| =", abs(y)) # Betrag von y + +elif choice == "1": + print("x + y =", x + y) # Summe + +elif choice == "2": + print("x * y =", x * y) # Produkt + +elif choice == "3": + print("x - y =", x - y) # Differenz + print("y - x =", y - x) # Differenz + +elif choice == "4": + print("x / y =", x / y) # Quotient + print("y / x =", y / x) # Quotient + +elif choice == "5": + print("x % y =", x % y) # Modulo Division + print("y % x =", y % x) # Modulo Division + +elif choice == "6": + print("sqrt(x) =", math.sqrt(x)) # Quadratwurzel + print("sqrt(y) =", math.sqrt(y)) # Quadratwurzel + +elif choice == "7": + print("x ^ y =", pow(x, y)) # Potenz + print("y ^ x =", pow(y, x)) # Potenz + +elif choice == "q" or choice == "Q": + # Alternativ: choice.upper() == "Q" + print("Auf Wiedersehen") + sys.exit(0) + +else: + print("Falsche Eingabe") + sys.exit(1) diff --git a/Level_02/Beispielcode/calculator02_while.py b/Level_02/Beispielcode/calculator02_while.py new file mode 100644 index 0000000..90ded72 --- /dev/null +++ b/Level_02/Beispielcode/calculator02_while.py @@ -0,0 +1,92 @@ +""" +Das folgende Programm ist ein einfacher Taschenrechner. + +Nach dem Eingeben zweier Zahlen kann eine Operation ausgewählt werden. +Anschließend wird nach neuen Zahlen gefragt. +""" + +# Für die Berechnung der Quadratwurzel wird die math Bibliothek benötigt, +# des Weiteren wird zum vorzeitigen Beenden die sys Bibliothek benötigt. +from math import sqrt +import sys + +# Zuerst eine Willkommensnachricht +print() +print("Dies ist ein einfacher Taschenrechner.") +print() + +# Das Menü wird angezeigt: +print("0: Betrag") +print("1: Summe") +print("2: Produkt") +print("3: Differenz") +print("4: Quotient") +print("5: Modulo Division") +print("6: Quadratwurzel") +print("7: Potenz") +print("8: Fakultät") +print("q: Beenden") +print() + +# Das Programm läuft in einer Endlosschleife und wird durch eine entsprechende +# Nutzereingabe beendet. +while True: + choice = input("Bitte eine Operation auswählen: ") + + # Falls der Benutzer ein "q" eingibt soll das Programm beendet werden + if choice.upper() == "Q": + print("Auf Wiedersehen") + sys.exit(0) + + x = input("Bitte eine ganze Zahl eingeben: ") + if choice not in ("0", "6", "8"): + # Diese Operationen benötigen mehr als einen Wert + y = input("Bitte eine weitere ganze Zahl eingeben: ") + y = int(y) + + # Die Eingabe wird in einen Integer umgewandelt + x = int(x) + + if choice == "0": + print("Betrag: |x| =", abs(x)) # Betrag von x + + elif choice == "1": + print("Summe: x + y =", x + y) # Summe + + elif choice == "2": + print("Produkt: x * y =", x * y) # Produkt + + elif choice == "3": + print("Differenz:") + print("x - y =", x - y) # Differenz + print("y - x =", y - x) # Differenz + + elif choice == "4": + print("Quotient:") + print("x / y =", x / y) # Quotient + print("y / x =", y / x) # Quotient + + elif choice == "5": + print("Rest:") + print("x % y =", x % y) # Modulo Division + print("y % x =", y % x) # Modulo Division + + elif choice == "6": + print("Quadratwurzel: sqrt(x) =", sqrt(x)) # Quadratwurzel + + elif choice == "7": + print("Potenz:") + print("x ^ y =", pow(x, y)) # Potenz + print("y ^ x =", pow(y, x)) # Potenz + + elif choice == "8": + tmp = 1 + for i in range(2, x + 1): + tmp = tmp * i + print("Fakultät: x! =", str(tmp)) + + else: + print("Ungültige Eingabe") + continue + + print("") diff --git a/Level_02/Beispielcode/cinema_if.py b/Level_02/Beispielcode/cinema_if.py new file mode 100644 index 0000000..f19dde2 --- /dev/null +++ b/Level_02/Beispielcode/cinema_if.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +age_str: str = input("Wie alt bist du? ") + +if age_str.isdigit(): + age_int: int = int(age_str) +else: + print("Bitte gib eine Zahl als Alter ein.") + exit() + +fsk_shrek = 6 +fsk_avengers = 12 + +print("Folgende Filme könntest du dir ansehen: ") + +if age_int >= fsk_avengers: + print("Marvel: The Avengers") + +elif age_int >= fsk_shrek: + print("Shrek") +else: + print("Leider haben wir keine Filme für dich im Angebot.") diff --git a/Level_02/Beispielcode/cinema_while.py b/Level_02/Beispielcode/cinema_while.py new file mode 100644 index 0000000..88dc130 --- /dev/null +++ b/Level_02/Beispielcode/cinema_while.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +fsk_shrek = 6 +fsk_avengers = 12 + +counter: int = 0 +while counter < 3: + age_str: str = input("Wie alt bist du? ") + + if age_str.isdigit(): + age_int: int = int(age_str) + break + + else: + print("Bitte gib eine Zahl als Alter ein.") + + counter += 1 +else: + age_int: int = 7 + print("Wenn du uns dein Alter nicht sagen möchtest, müssen wir es schätzen.") + print(f"Du bist wohl {age_int} Jahre alt.") + +print("Folgende Filme könntest du dir ansehen: ") + +if age_int >= fsk_avengers: + print("Marvel: The Avengers") + +elif age_int >= fsk_shrek: + print("Shrek") + +else: + print("Leider haben wir keine Filme für dich im Angebot.") diff --git a/Level_02/Beispielcode/ggT.py b/Level_02/Beispielcode/ggT.py new file mode 100755 index 0000000..fc20958 --- /dev/null +++ b/Level_02/Beispielcode/ggT.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +""" +Dieses Programm implementiert den euklidischen Algorithmus zur Bestimmung des größten gemeinsamen Teilers zweier Zahlen iterativ. + +(In Level 5 findet sich eine rekursive Implementation.) +""" + +# Eingabe +a = int(input("erste Zahl eingeben: ")) +b = int(input("zweite Zahl eingeben: ")) + +# Beide Zahlen sollten positiv sein. +# Wir nehmen einfach den Betrag. +a = abs(a) +b = abs(b) + +# a soll größer sein als b. +# Falls das nicht bereits der Fall ist, +# tauschen wir die beiden einfach. +if b > a: + a, b = b, a + +# Wenn b Null ist, sind wir fertig und a ist der ggT. +# Ansonsten müssen wir (nochmal) rechnen. +while b != 0: + # Teile a mit Rest durch b; + # setze a auf b + # und b auf den Rest. + a, b = b, a%b + +# Ausgabe +print("Der größte gemeinsame Teiler dieser Zahlen ist:", a) diff --git a/Level_02/Level_2.ipynb b/Level_02/Level_2.ipynb new file mode 100644 index 0000000..83f5b58 --- /dev/null +++ b/Level_02/Level_2.ipynb @@ -0,0 +1,507 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "# Level 2" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "## Einstieg\n", + "\n", + "In diesem Level lernst du mit dem `boolean` einen neuen Datentypen kennen. Ebenso lernst du zwei neue Kontrollstrukturen kennen: die `if`-Bedingung und die `while`-Schleife.\n", + "Diese Kontrollstrukturen ermöglichen es dir nach Abschluss dieses Levels komplexere Algorithmen zu implementieren und anspruchsvollere Python-Skripte zu schreiben." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "eingabe = input(\"Bitte eine Zahl eingeben: \")\n", + "zahl = int(eingabe)\n", + "print(zahl)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "Zum Einstieg betrachte den obigen Code-Ausschnitt. Es soll eine Zahl vom Benutzer eingegeben werden. In Level 1 hast du gelernt, dass die `input()`-Funktion stets einen string zurückliefert. Daher wird im obigen Beispiel die Eingabe mittels der `int()`-Funktion in einen integer umgewandelt. Probleme treten auf, wenn der Benutzer keine gültige Zahl eingibt. Die Verarbeitung einer fehlerhaften Eingabe ist durch eine `if`-Bedingung möglich. Doch zuerst solltest du einmal verstehen was ein `boolean` ist." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "## Der Typ boolean\n", + "\n", + "Ein __boolean__ ist ein Datentyp, der einen Wahrheitswert enthält. Valide Werte für einen boolean sind die Literale `True` und `False`.\n", + "Wie die Werte anderer Datentypen kannst du diese beiden Werte in einer Variablen speichern.\n", + "\n", + "```python\n", + "wahr = True\n", + "falsch = False\n", + "```\n", + "\n", + "Ebenso wie für die Datentypen, die du bisher kennengelernt hast, gibt es auch für den boolean eine Funktion, welche einen beliebigen Ausdruck in einen boolean-Wert umwandelt. In diesem Fall die `bool()` Funktion. Im folgendem siehst du ein paar Beispiele für Umwandlungen dir bekannter Datentypen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# True\n", + "print(f'bool(23): {bool(23)}')\n", + "print(f'bool(4.2): {bool(4.2)}')\n", + "print(f'bool(\"pythonfoo\"): {bool(\"pythonfoo\")}')\n", + "\n", + "# False\n", + "print(f'bool(0): {bool(0)}')\n", + "print(f'bool(0.0): {bool(0.0)}')\n", + "print(f'bool(\"\"): {bool(\"\")}')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "Ob ein Wert umgewandelt in einen boolean `True` oder `False` zurückgibt, hängt dabei vom Typen des Wertes ab. \n", + "Für die Datentypen, die du bisher kennengelernt hast, kannst du dir merken:\n", + "\n", + "1. Ein integer ist `True`, solange er nicht `0` ist\n", + "2. Ein float ist `True`, solange er nicht `0.0` ist\n", + "3. Ein string ist `True`, solange er nicht leer, d.h. `''` ist" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(bool(\"\"))\n", + "print(bool(0))\n", + "print(bool(0.0))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "Ein Anwendungsfall von boolean-Werten, der dir sehr häufig begegnen wird, sind Vergleichsoperatoren. Du kennst sicherlich Vergleiche wie \"größer als\" oder \"kleiner gleich\" aus der Mathematik. Diese kannst du ebenfalls in Python benutzen. Im folgenden siehst eine Auflistung der Vergleichsoperatoren und jeweils ein wahres und ein falsches Beispiel.\n", + "\n", + "1. Äquivalenz: `==` prüft ob zwei Ausdrücke denselben Wert haben.\n", + " ```python\n", + " 23 == 15 + 8 # True\n", + " 23 == 27 # False\n", + " ```\n", + "2. Nicht-Äquivalenz: `!=` prüft ob zwei Ausdrücke einen unterschiedlichen Wert haben.\n", + " ```python\n", + " 23 != 42 # True\n", + " 23 != 23 # False\n", + " ```\n", + "3. Größer: `>` prüft ob der erste Ausdruck echt größer als der zweite Ausdruck ist.\n", + " ```python\n", + " 23 > 2.3 # True\n", + " 23 > 24 # False\n", + " ```\n", + "4. Kleiner: `<` prüft ob der erste Ausdruck echt größer als der zweite Ausdruck ist.\n", + " ```python\n", + " 23 < 42 # True\n", + " 23 < 2.7 # False\n", + " ```\n", + "5. Größer gleich: `>=` prüft ob der erste Ausdruck größer oder gleich dem zweiten Ausdruck ist.\n", + " ```python\n", + " 23 >= 23 # True\n", + " 23 >= 24 # False\n", + " ```\n", + "6. Kleiner gleich: `<=` prüft ob der erste Ausdruck kleiner oder gleich dem zweiten Ausdruck ist.\n", + " ```python\n", + " 23 >= 42 # True\n", + " 23 >= 42 # False\n", + " ```\n", + "7. Gleichheit: `is` ist ein Schlüsselwort und prüft ob zwei Ausdrücke gleich sind.\n", + " ```python\n", + " 23 is 23 # True\n", + " 23 is 23.0 # False\n", + " ```\n", + " Das Schlüsselwort `is` findet bei primitiven, unveränderlichen Datentypen kaum Anwendung, da es sich bei diesen nicht vom Äquivalenzoperator `==` unterscheidet." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "Genauso wie integer und floats gibt es auch für booleans Operatoren:\n", + "\n", + "1. `and` das logische \"und\"\n", + "2. `or` das logische \"oder\"\n", + "3. `not` die logische Negation\n", + "\n", + "Außerdem lässt sich auch xor (`^`) auf booleans anwenden. \n", + "Die Operatoren `and` und `or` lassen sich nicht nur auf booleans anwenden. Bei Anwendung mit anderen Datentypen weisen sie eien erweiterte Funktion auf." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "scrolled": false, + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "not True: False\n", + "True or False: True\n", + "True and False: False\n", + "True ^ False: True\n" + ] + } + ], + "source": [ + "print(\"not True:\", not True)\n", + "print(\"True or False:\", True or False)\n", + "print(\"True and False:\", True and False)\n", + "print(\"True ^ False:\", True ^ False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## if-Bedingung\n", + "\n", + "Nachdem du den Datentyp boolean kennengelernt hast, lernst du nun, wie du eine `if`-Bedingung benutzt. Eine `if`-Bedingung dient dazu einen Code-Abschnitt nur auszuführen, wenn eine Bedingung erfüllt ist. Bei dieser Bedingung handelt es sich um einen boolschen Ausdruck. Im folgendem Code-Ausschnitt siehst du eine beispielhafte if-Bedingung.\n", + "\n", + "```python\n", + "if True:\n", + " print(\"True\")\n", + "```\n", + "\n", + "### Einrückung und Gültigkeitsbereiche\n", + "\n", + "Beachte, dass der Code, welcher von der Bedingung beeinflusst werden soll um vier Leerzeichen eingerückt ist. Das ist kein Zufall. Anders als andere Programmiersprachen erkennt Python die Gültigkeitsbereiche nicht anhand von Klammern (Java benutzt zum Beispiel `{` und `}`), sondern anhand der Einrückung am Anfang der Zeile. Zu einem Gültigkeitsbereich gehören dabei alle aufeinanderfolgenden Zeilen gleicher Einrückung.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "eingabe = input(\"Bitte etwas eingeben: \")\n", + "if eingabe: # alternativ: bool(eingabe) oder eingabe != \"\"\n", + " print(eingabe)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Im obigen Beispiel siehst du ein interaktives Beispiel für eine einfache if-Bedingung. In dem Fall soll überprüft werden, ob die Eingabe leer ist. Beachte, dass die als Bedingung lediglich die Variable `eingabe` also ein string benutzt wird. Dies ist deshalb möglich, da der Python-Interpreter intern auf den Ausdruck, welchen du als Bedingung angibst, versucht mittels der `bool()`-Funktion in einen `boolean` umzuwandeln. \n", + "\n", + "Eine if-Bedingung kann auch beliebig viele (optionale) `elif`-Zweige und einen (ebenfalls optionalen) `else`-Zweige enthalten. Das Schlüsselwort `elif` ist eine Abkürzung für `else if`. In einem `elif`-Zweig kannst du weitere Bedingungen prüfen. Es wird aber stets der erste Zweig ausgeführt, dessen Bedingung wahr ist. Der `else`-Zweig wird nur dann ausgeführt, wenn keine Bedingung wahr ist. Unten siehst du den schematischen Aufbau einer if-Bedingung (Achtung es handelt sich *nicht* um validen Python-Code).\n", + "```python\n", + "if Bedingung:\n", + " Anweisungen\n", + "\n", + "elif Bedingung:\n", + " Anweisungen\n", + "\n", + "...\n", + "\n", + "else:\n", + " Anweisungen\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wenn du dich an das Problem im [Einstieg](#einstieg) erinnerst kannst du nun die if-Bedingung anwenden, um einen `Value-Error` bei Eingabe von falschen Werten zu vermeiden." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "eingabe = input(\"Bitte etwas eingeben: \")\n", + "\n", + "if eingabe.isdigit():\n", + " zahl = int(eingabe)\n", + " print(zahl)\n", + "\n", + "else:\n", + " print(\"Ungültige Eingabe:\", eingabe)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Im obigen Beispiel wird die `str.isdigit()` Methode verwendet. Diese Methode gibt `True` zurück, sobald alle Zeichen in dem string Nummern sind. Durch Benutzung dieser Methode kannst du verhindern, dass dein Programm wegen eines `ValueError`s abstürzt. Du kannst natürlich auch zusätzlich prüfen, ob die Eingabe leer ist:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "23 ist eine gültige Zahl.\n" + ] + } + ], + "source": [ + "eingabe = input(\"Bitte eine Zahl eingeben: \")\n", + "\n", + "if eingabe.isdigit():\n", + " # die Eingabe ist eine gültige Zahl\n", + " zahl = int(eingabe)\n", + " print(zahl, \"ist eine gültige Zahl.\")\n", + "\n", + "elif not eingabe:\n", + " # die Eingabe ist leer\n", + " print(\"Die Eingabe ist leer\")\n", + "\n", + "else:\n", + " # die Eingabe ist nicht leer, aber auch keine\n", + " # gültige Zahl\n", + " print(\"Die Eingabe '\" + eingabe + \"' ist keine gültige Zahl\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Du kannst if-Bedingungen auch ineinander verschachteln. Das kann bei komplexeren Bedingungen hilfreich sein. Unten siehst du das Beispiel von oben als verschachtelte if-Bedingung. Gerade bei längeren Bedingungen kann es hilfreich sein, diese zu verschachteln. Beachte beim Verschachteln von if-Bedingungen die Einrückung!" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Die Eingabe 23 ist eine gültige Zahl.\n" + ] + } + ], + "source": [ + "eingabe = input(\"Bitte eine Zahl eingeben: \")\n", + "\n", + "if eingabe:\n", + " if eingabe.isdigit():\n", + " # die Eingabe ist eine gültige Zahl\n", + " zahl = int(eingabe)\n", + " print(\"Die Eingabe\", zahl, \" ist eine gültige Zahl.\")\n", + " else:\n", + " # die Eingabe ist keine gültige Zahl\n", + " print(\"Die Eingabe\", eingabe, \" ist keine gültige Zahl\")\n", + "\n", + "else:\n", + " # die Eingabe ist leer\n", + " print(\"Die Eingabe ist leer.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## while-Schleife\n", + "\n", + "Bisher hattest du keine Möglichkeit Programmcode wiederholt auszuführen. Das wäre aber sehr hilfreich, damit du nicht wiederholt den selben Code schreiben musst. In Python wird dies (wie in vielen anderen Programmiersprachen auch) mit Schleifen realisiert. In Python gibt es zwei Arten von Schleifen: `While`-Schleife und die `for`-Schleife. In diesem Level lernst du die `while`-Schleife kennen. Du wirst feststellen, dass sie große Gemeinsamkeiten mit der `if`-Bedingung aufweist.\n", + "\n", + "Hier siehst du den Aufbau der `while`-Schleife:\n", + "\n", + "```python\n", + "while Bedingung:\n", + " Befehle\n", + "```\n", + "\n", + "Im Schleifenkopf legst du eine Bedingung fest. Diese Bedingung ist ein boolscher Ausdruck und wird auf seinen Wahrheitswert geprüft. Ist die Bedingung wahr, werden die Befehle im Schleifenrumpf ausgeführt. Danach wird erneut die Bedingung im Schleifenkopf auf ihren Wahrheitswert getestet, ist die Bedingung immer noch war, wird erneut der Schleifenrumpf ausgeführt. Ist die Bedingung jedoch falsch, wird der Durchlauf der Schleife beendet.\n", + "\n", + "Wie du vielleicht bemerkt hast, sind die Voraussetzungen an eine `while`-Schleife sehr abstrakt (ähnlich wie bei einer `if`-Bedingung). Dadurch kannst du viele verschiedene Anwendungsfälle mit einer `while`-Schleife darstellen.\n", + "\n", + "Im folgenden Codeblock siehst du eine Schleife, die eine `integer` Variable hochzählt. Die Bedingung vergleicht dabei diese Variable mit einem Maximalwert (in dem Fall `10`). Im Beispiel wird die Variable lediglich ausgegeben, du kannst aber natürlich alles erdenkliche mit dem `integer` anstellen." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n", + "5\n", + "6\n", + "7\n", + "8\n", + "9\n" + ] + } + ], + "source": [ + "counter = 0\n", + "maximum = 10\n", + "while counter < maximum:\n", + " print(counter)\n", + " counter += 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Du solltest immer darauf achten keine Endlosschleife zu erschaffen. Wenn aus irgendeinem Grund deine Abbruchbedingung niemals `False` werden kann, wird die Schleife endlos laufen. In der Zählschleife oben kann dir dies zum Beispiel leicht passieren, wenn du die Inkrementierung (`counter += 1`) vergisst. In dem Fall würde die `counter` Variable niemals den Wert ändern und daher für immer `< maximum` bleiben. In den Konsole kannst du die Ausführung eines Python-Programms durch die Tastenkombination `Strg + C` abbrechen.\n", + "\n", + "Es gibt noch zwei Schlüsselwörter, die dir mehr Kontrolle über den Schleifendurchlauf geben: `break`, `continue` und `else`. Das `break`-Schlüsselwort beendet den Durchlauf der Schleife und springt an Ende. Das `continue`-Schlüsselwort überspringt den Rest des Codeblocks und springt zum Schleifenkopf. Das `else`-Schlüsselwort kann am Ende einer Schleife benutzt werden. Der Codeblock unter dem `else`-Schlüsselwort wird ausschließlich dann ausgeführt, wenn der Durchlauf der Schleife nicht durch ein `break` abgebrochen wurde." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Zahlen raten\n", + "gesucht = 56\n", + "versuche = 10\n", + "zaehler = 0\n", + "print(\"Die gesuchte Zahl x ist 0 < x < 100.\")\n", + "\n", + "while zaehler < versuche:\n", + " eingabe = input(\": \")\n", + " zaehler += 1\n", + "\n", + " # eingabe überprüfen\n", + " if eingabe.isdigit():\n", + " zahl = int(eingabe)\n", + " else:\n", + " print(\"Ungültige Eingabe.\")\n", + " continue\n", + "\n", + " # Benutzer Feedback\n", + " if zahl == gesucht:\n", + " print(\"Richtig!\")\n", + " break\n", + " else:\n", + " if zahl > gesucht:\n", + " print(\"Kleiner.\")\n", + " else:\n", + " print(\"Größer\")\n", + " print(\"Noch\", versuche - zaehler, \"Versuche.\")\n", + "\n", + "\n", + "else:\n", + " # kein break <=> zahl wurde nicht erraten\n", + " print(\"Die Zahl wurde nicht erraten.\")\n", + " print(\"Die richtige Zahl war:\", gesucht)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Oben siehst du ein etwas längeres Beispiel, darin sind alle Elemente dieses Levels vereint. Du siehst sowohl `if`-Bedingungen als auch eine `while`-Schleife. In der Schleife werden die drei erwähnten Schlüsselwörter `break`, `continue` und `else` benutzt. In dem Beispiel soll vom Benutzer eine Zahl geraten werden. Dazu hat der Benutzer 10 Versuche. Bei jeder gültigen Eingabe des Benutzers wird dabei eine Tendenz (\"Größer\" oder \"Kleiner\") ausgegeben. Falls der Benutzer eine ungültige Eingabe tätigt, wird der Durchlauf der Schleife übersprungen, gibt der Benutzer die gesuchte Zahl ein, wird der Schleifendurchlauf beendet.\n", + "\n", + "## Rückblick\n", + "\n", + "Im vorherigen Level hast du gelernt, Eingaben vom Benutzer entgegen zu nehmen, diese zu verarbeiten und das Ergebnis an den Benutzer auszugeben.\n", + "In diesem Level hast du zwei Kontrollstrukturen kennengelernt, die `if`-Bedingung und die `while`-Schleife. Dazu hast du den Datentyp `boolean` kennengelernt. Durch diese beiden Kontrollstrukturen kannst du komplexere Programme schreiben. Durch die `if`-Bedingung kannst du auf Eingaben des Benutzers oder Änderungen der Umgebung reagieren. Mit der `while`-Schleife kannst du zum Beispiel verschiedene mathematische Algorithmen implementieren." + ] + } + ], + "metadata": { + "celltoolbar": "Raw Cell Format", + "kernelspec": { + "display_name": "Python 3.10.6 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + }, + "vscode": { + "interpreter": { + "hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git "a/Level_02/L\303\266sungen/diamond.py" "b/Level_02/L\303\266sungen/diamond.py" new file mode 100644 index 0000000..480c130 --- /dev/null +++ "b/Level_02/L\303\266sungen/diamond.py" @@ -0,0 +1,13 @@ +max_width = int(input("Maximale Breite: ")) +min_width = 0 +zeichen = input("Zeichen: ") +assert len(zeichen) == 1 + +cur_width = 1 +while cur_width * 2 <= max_width: + print(" " * (max_width - cur_width) + zeichen*(cur_width * 2 - 1)) + cur_width += 1 + +while cur_width * 2 >= min_width: + print(" " * (max_width - cur_width) + zeichen*(cur_width * 2 - 1)) + cur_width -= 1 diff --git "a/Level_02/L\303\266sungen/password.py" "b/Level_02/L\303\266sungen/password.py" new file mode 100644 index 0000000..d13110a --- /dev/null +++ "b/Level_02/L\303\266sungen/password.py" @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +from getpass import getpass +from sys import exit + +PWD = "123456" + +print("Hallo, bitte gib dein Passwort ein:") + +counter = 0 +while counter < 3: + eingabe = getpass("> ") + if eingabe == PWD: + print("Richtig.") + break + else: + print("Falsch.") + counter += 1 +else: + print("leider zu oft falsch :(") + exit() + +print("Herzlich Willkommen") diff --git a/Level_02/README.md b/Level_02/README.md new file mode 100644 index 0000000..5c46bef --- /dev/null +++ b/Level_02/README.md @@ -0,0 +1,58 @@ +# Level 2 + +In Level 1 hast du gelernt Eingaben in der Konsole vom Benutzer entgegen zu nehmen und, diese EIngaben zu verarbeiten und die Ergebnisse dieser Verarbeitung in der Konsole auszugeben. + +In Level 2 wirst die `if`-Bedingung kennenlernen, die es dir ermöglicht Bedingungen zu prüfen, die erfüllt sein müssen, damit ein Codeabschnitt ausgeführt werden kann. +Des Weiteren wirst du die `while`-Schleife kennenlernen, welche einen Codeabschnitt wiederholt ausführt, solange eine Bedingung erfüllt ist. +Im Zusammenhang mit der `if`-Bedingung und der `while`-Schleife wirst du den Datentypen `boolean` kennenlernen. Dieser Datentyp beinhaltet Wahrheitswerte. +Am Ende des Levels wirst bereits in der Lage sein komplexere Programme umzusetzen. + +Um mit diesem Level zu starten navigiere zur [Level2.ipynb](https://github.com/pythonfoo/pythonfooLite/blob/master/Level_02/Level_2.ipynb) Datei im Code Repository. + +## Aufgaben + +Die folgenden Aufgaben sollen dir helfen, die in diesem Level erlangten Kenntnisse unter die Probe zu stellen. Wie immer kannst du dich bei Fragen oder Problemen gerne an uns wenden. + +### 2.1 password.py + +* Schreibe ein Programm, das ein Passwort entgegennimmt, es mit einem intern + gespeicherten Passwort vergleicht und eine Begrüßungsnachricht ausgibt, falls das + Passwort richtig war. +* Ändere dein Programm so ab, dass der Benutzer auch eine Nachricht bekommt, wenn + das Passwort falsch war. +* Ändere dein Programm so ab, dass der Benutzer 3 Versuche hat, das Passwort richtig + einzugeben. + +### 2.2 diamond.py + +* Schreibe ein Programm, das die unten abgebildete ASCII-Art im Terminal darstellt. +* Ändere dein Programm so ab, dass die maximale Breite der Raute vom Benutzer angegeben werden kann. +* Ändere dein Programm so ab, dass das Zeichen, aus dem die Raute gebildet wird, vom Benutzer eingegeben werden kann. + +``` + # + ### + ##### + ### + # +``` + +Nach erfolgreicher Bearbeitung der Aufgabe sollte das Programm wie folgt ablaufen: + +* Der Benutzer gibt eine maximale Breite an Zeichen ein. +* Der Benutzer gibt ein Zeichen ein. +* Das Programm erstellt eine Raute entsprechend der maximalen Breite mit dem angegebenen Zeichen und gibt diese Raute aus. + +### 2.3 hangman_v1.py + +In dieser Aufgabe sollst du eine einfache Version des Kinderspiels Galgenmännchen erstellen. Diese Aufgabe ähnelt sehr der Aufgabe **password.py**. +Zuerst soll ein Wort eingegeben werden können. Dieses Wort soll nun durch Eingabe von Buchstaben erraten werden. Dabei gibt es ein Limit für die Anzahl an Fehlern. +Implementiere eine Version des Spiels, welche folgende Anforderungen erfüllt: + +* Das Spiel ist gewonnen, wenn das Wort erraten wurde und das Fehlerlimit noch nicht erreicht wurde. +* Das Spiel ist verloren, wenn das Fehlerlimit erreicht wurde und das Wort noch nicht erreicht worden ist. +* Wird ein Buchstabe vom Benutzer eingegeben, welcher im Wort vorkommt wird das Auftauchen dieses Buchstaben im Wort ausgegeben. +* Wird ein Buchstabe vom Benutzer eingegeben, welcher nicht im Wort enthalten ist wird dies als Fehler gewertet. +* Enthält eine Eingabe des Benutzers mehr als ein Zeichen, wird dies ebenfalls als Fehler gewertet. +* Bei der Eingabe von Buchstaben soll die Groß- und Kleinschreibung keine Rolle spielen. +* Die aktuelle Fehleranzahl soll stets für den Benutzer sichtbar sein. \ No newline at end of file diff --git a/Level_02/boolean.py b/Level_02/boolean.py deleted file mode 100755 index efdda09..0000000 --- a/Level_02/boolean.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python3 - -# Der Datentyp : -boolean = True -boolean2 = False - - -# Vergleichen von zwei boolean: -bool_result = boolean == boolean2 -bool_result2 = boolean and boolean2 -bool_result3 = boolean or boolean2 - -print(bool_result) -print(bool_result2) -print(bool_result3) -print() - - -# Der not-Operator: - -boolean3 = not boolean -print(boolean3) \ No newline at end of file diff --git a/Level_02/buggy02.py b/Level_02/buggy02.py new file mode 100644 index 0000000..69cc842 --- /dev/null +++ b/Level_02/buggy02.py @@ -0,0 +1,16 @@ +# Dieses Programm enthält verschiedene Fehler, +# die Aufgabe besteht darin die Fahler zu finden +# und zu beheben. +import getpass, sys + +pass = "Geheim" + +eingabe = getpass.getpass("Bitte geben Sie das Passwort ein: \n") + +if eingabe == pass: + print("Das Passwort war richtig.") + print("Bitte fahren Sie fort.") + +else: + print("Das Passwort war falsch.') + sys.exit() diff --git a/Level_02/if.py b/Level_02/if.py deleted file mode 100755 index 31ba5e7..0000000 --- a/Level_02/if.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python3 - -# Die if-Bedingung: -boolean3 = True - -if boolean3 == True: - print(True) - -# Wenn nur geprüft werden soll, ob ein Ausdruck -# ist, kann das '== True' weggelassen werden, -# da der Compiler überprüft, ob der Ausdruck True -# ist. - -if boolean3: - print(True) - - -# if-Bedingung mit else-Zweig: -summertime = True - -if summertime: - print("Yeah, it's summer!") -else: - print("Ohh, it's winter!") - - -# if-Bedingung zum Vergleichen von int-Werten: -a = 5 -b = 10 -if a > b: - print(a) -else: - print(b) - -# Wichtig: Auf die Einrückung achten! - -# if-Bedingung mit elif- und else-Zweig: - -a = 6 -b = 7 - -if a > b: - print("A") - -elif a == b: - print(" ") - -elif a < b: - print("B") - -else: - print("You broke the math.") - - -# Verschachtelte if-Bedingungen: - -a = 3 -b = 4 -c = 5 - -if a < b: - if b < c: - print("C ist der Größte!") - - else: - if b > c: - print("B ist der Größte!") - - else: - print("B und C sind die Größten!") - -else: - if a > b: - if a > c: - print("A ist der Größte!") - - else: - if a < c: - print("C ist der Größte!") - - else: - print("A und C sind die Größten!") - -# Wichtig: Einrückung beibehalten! \ No newline at end of file diff --git a/Level_02/passwort.py b/Level_02/passwort.py deleted file mode 100755 index e77de12..0000000 --- a/Level_02/passwort.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 - -from getpass import getpass - -PWD = "123456" - -eingabe = getpass() - -if eingabe == PWD: - print("Richtig.") -elif eingabe in PWD: - print("Fast.") -else: - print("Falsch.") diff --git a/Level_03/Beispielcode/caesar_decode.py b/Level_03/Beispielcode/caesar_decode.py new file mode 100644 index 0000000..5d03fa3 --- /dev/null +++ b/Level_03/Beispielcode/caesar_decode.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +""" +Dieses Programm implementiert die Cäsar-Chiffre, die schon Gaius Julius Cäsar +benutzt haben soll, um mit seinen Generälen vertraulich zu kommunizieren. +Es handelt sich dabei um eine mono-alphabetische Substitutionschiffre, das +bedeutet, jeder Buchstabe im Klartext wird durch einen anderen Buchstaben aus +dem Alphabet ersetzt, bei der Cäsar-Chiffre wird dieser zweite Buchstaben durch +Verschiebung um einen festen Wert ermittelt. Dieser feste Wert bildet dabei den +Schlüssel. https://de.wikipedia.org/wiki/Caesar-Verschl%C3%BCsselung + +Dieses Programm kümmert sich um die Verschlüsselung mit Hilfe der +Caesarchiffre, wohingegen sich caesar_encode.py um die Verschlüsselung kümmert. +""" + +secret = input("Bitte den Geheimtext eingeben: \n") +key = input("Bitte die Verschiebungszahl eingaben: ") +key = int(key) + +secret = secret.upper() + +# An dieser Stelle wird das Alphabet durch die ASCII Werte der Buchstaben +# erzeugt +alphabet = [] +for i in range(26): + alphabet += chr(65 + i) + +# Später soll in plaintext der Klartext stehen +plaintext = "" + +for char in secret: + # Falls der Buchstabe nicht in dem Alphabet vorhanden ist, wird er auch + # nicht entschlüsselt + if char not in alphabet: + plaintext += char + continue + + tmp = alphabet.index(char) + new_char = alphabet[(tmp - key) % len(alphabet)] + plaintext += new_char + +print(plaintext) diff --git a/Level_03/Beispielcode/caesar_encode.py b/Level_03/Beispielcode/caesar_encode.py new file mode 100644 index 0000000..4e16608 --- /dev/null +++ b/Level_03/Beispielcode/caesar_encode.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +""" +Dieses Programm implementiert die Cäsar-Chiffre, die schon Gaius Julius Cäsar +benutzt haben soll, um mit seinen Generälen vertraulich zu kommunizieren. +Es handelt sich dabei um eine mono-alphabetische Substitutionschiffre, das +bedeutet, jeder Buchstabe im Klartext wird durch einen anderen Buchstaben aus +dem Alphabet ersetzt, bei der Cäsar-Chiffre wird dieser zweite Buchstaben durch +Verschiebung um einen festen Wert ermittelt. Dieser feste Wert bildet dabei den +Schlüssel. https://de.wikipedia.org/wiki/Caesar-Verschl%C3%BCsselung + +Dieses Programm kümmert sich um die Verschlüsselung mit Hilfe der +Caesarchiffre, wohingegen sich caesar_decode.py um die Entschlüsselung kümmert. +""" + +plaintext = input("Bitte den Klartext eingeben: \n") +key = input("Bitte die Verschiebungszahl eingaben: ") +key = int(key) + +plaintext = plaintext.upper() + +# An dieser Stelle wird das Alphabet durch die ASCII Werte der Buchstaben +# erzeugt +alphabet = [] +for i in range(26): + alphabet += chr(65 + i) + +# Später soll in secret der verschlüsselte Text stehen +secret = "" + +for char in plaintext: + # Falls der Buchstabe nicht in dem Alphabet vorhanden ist, wird er auch + # nicht verschlüsselt + if char not in alphabet: + secret += char + continue + + tmp = alphabet.index(char) + new_char = alphabet[(tmp + key) % len(alphabet)] + secret += new_char + +print(secret) diff --git a/Level_03/Beispielcode/fibonacci.py b/Level_03/Beispielcode/fibonacci.py new file mode 100755 index 0000000..99da0fd --- /dev/null +++ b/Level_03/Beispielcode/fibonacci.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +""" +Dieses Programm berechnet die Fibonacci-Reihe (iterativ). +Dabei gilt: Die Summe zweier Elemente ergibt das Nächste. + +(In Level 5 findet sich eine rekursive Implementation.) +""" + +anzahl = int(input("Wie viele Elemente sollen berechnet werden? ")) + +# Die ersten beiden Elemente sind fix: +current = 0 # current ist das jeweils aktuelle Element. +next = 1 # next ist das jeweils nächste Element. + +for n in range(anzahl): # type: int + # Gebe das aktuelle Element aus: + print(" * ", current) + + # Setze das aktuelle Element eins weiter + # und das nächste auf die Summe des letzten und des aktuellen Elements. + current, next = next, current + next diff --git a/Level_03/Beispielcode/fizzbuzz.py b/Level_03/Beispielcode/fizzbuzz.py new file mode 100644 index 0000000..64af435 --- /dev/null +++ b/Level_03/Beispielcode/fizzbuzz.py @@ -0,0 +1,7 @@ +for i in range(1, 16): + output = "" + if i % 3 == 0: + output += "fizz" + if i % 5 == 0: + output += "buzz" + print(output or i) diff --git a/Level_03/pwd-schleifen.py b/Level_03/Beispielcode/pwd-schleifen.py similarity index 69% rename from Level_03/pwd-schleifen.py rename to Level_03/Beispielcode/pwd-schleifen.py index 2d8dcba..24ead40 100755 --- a/Level_03/pwd-schleifen.py +++ b/Level_03/Beispielcode/pwd-schleifen.py @@ -6,7 +6,7 @@ N_VERSUCHE = 3 for x in range(N_VERSUCHE): - eingabe = getpass() + eingabe = getpass() # type: str if eingabe == PWD: print("Richtig.") @@ -16,8 +16,7 @@ else: print("Falsch.") else: - print("Passwort {} mal falsch eingegeben.".format(N_VERSUCHE)) - import sys - sys.exit(1) + print("Passwort", N_VERSUCHE, "mal falsch eingegeben.") + exit(1) print("...") diff --git a/Level_03/Level_3.ipynb b/Level_03/Level_3.ipynb new file mode 100644 index 0000000..d8c6c3a --- /dev/null +++ b/Level_03/Level_3.ipynb @@ -0,0 +1,2469 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Level 3\n", + "\n", + "In diesem Level lernen wir neue Datentypen, wie `list`, `tuple`, `dict`, `set` und `frozenset` kennen und lernen über Objekte dieser Typen mittels einer __for-Schleife__ zu iterieren. Wir werden die Schlüsselwörter `del` und `for` kennenlernen und auch den Schlüsselwörtern `in`, `break`, `continue` und `else` ein weiteres Mal begegnen.\n", + "\n", + "## Einstieg\n", + "Bisher können wir Werte in Variablen speichern, das funktioniert auch, solange wir wissen, wieviele Werte wir speichern müssen. Das muss aber nicht der Fall sein. Die Datentypen, die wir in diesem Level kennenlernen ermöglichen es meherere Werte in einem Objekt zu speichern. Jeder dieser Typen hat dabei seine Besonderheiten, die wir im Laufe des Levels lernen werden." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## list\n", + "Der `list` Typ ist der erste, den wir uns in diesem Level anschauen möchten. Er bietet viele Möglichkeiten an, ist einfach zu bedienen, weshalb er auch häufig benutzt wird. Im Gegensatz zu allen anderen Typen, die wir bereits kennengelernt haben und auch einigen anderen, die wir noch kennenlernen, ist die Liste ein veränderlicher Typ. Das heißt wir können ein `list` Objekt ändern und müssen es nicht überschreiben. Die Elemente eines `list` Objektes können einen beliebigen Typen haben." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Erstellen einer Liste\n", + "Zuerst erstellen wir eine leere Liste, entweder benutzen wir dafür die `list()` Funktion oder eckige Klammern `[]`, welche die Literale einer Liste darstellen." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "leer = list()\n", + "leer2 = []" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Es ist allerdings möglich eine Liste zu erstellen, die bereits Einträge enthält. Diese Einträge nennen wir _Elemente_. Für das erstellen können wir wieder die Literale nehmen oder die `list()` Funktion. Beim Benutzen der `list()` Funktion müssen wir allerdings beachten, dass diese ein Objekt in eine Liste umwandelt und das nicht mit allen Objekten geht. In dem Beispiel unten erstellen wir aus einem string eine Liste." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, True, 4.2, 'foo'] Länge: 4\n", + "['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a'] Länge: 11\n" + ] + } + ], + "source": [ + "liste = [0, True, 4.2, \"foo\"]\n", + "liste2 = list(\"abracadabra\")\n", + "print(liste, \"Länge:\", len(liste))\n", + "print(liste2, \"Länge:\", len(liste2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Operatoren\n", + "Für Listen gibt es ebenfalls einen `+` und einen `*` Operator:
\n", + "Beim `+` Operator wird eine Liste erstellt, die erst alle Elemente der ersten Liste und dann alle Elemente der zweiten Liste enthält.
\n", + "Beim `*` Operator muss der andere Wert neben der Liste ein integer sein. Es wird eine neue Liste erstellt, welche die Elemente der Liste entsprechend häufig wiederholt." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, True, 4.2, 'foo', 'a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a']\n", + "[0, True, 4.2, 'foo', 0, True, 4.2, 'foo']\n" + ] + } + ], + "source": [ + "liste = [0, True, 4.2, \"foo\"]\n", + "liste2 = list(\"abracadabra\")\n", + "print(liste + liste2)\n", + "print(liste * 2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Zugriff auf Elemente \n", + "Auf die Elemente einer Liste wird über deren __Index__ zugegriffen. Dieser ist ein integer startet beim ersten Element mit `0`." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 0\n", + "1 True\n", + "2 4.2\n", + "3 foo\n" + ] + } + ], + "source": [ + "liste = [0, True, 4.2, \"foo\"]\n", + "index = 0\n", + "length = len(liste)\n", + "while index < length:\n", + " element = liste[index]\n", + " print(index, element)\n", + " index = index + 1 " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Es ist allerdings auch möglich mit negativen Indices zu arbeiten. Diese starten beim letzten Element der Liste mit dem Index `-1`. Dadurch wird es möglich auf die letzten Elemente der Liste zuzugreifen ohne die `len()` Funktion benutzen zu müssen.
\n", + "So können wir die Liste von eben auch rückwärts durchlaufen:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-1 foo\n", + "-2 4.2\n", + "-3 True\n", + "-4 0\n" + ] + } + ], + "source": [ + "liste = [0, True, 4.2, \"foo\"]\n", + "index = -1\n", + "length = -1 * len(liste)\n", + "while index >= length:\n", + " element = liste[index]\n", + " print(index, element)\n", + " index = index - 1 " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Slicing\n", + "Es ist nicht nur möglich auf die gesamte Liste oder auf einzelne Elemente zuzugreifen. Mit slicing können wir auch auf Teile einer Liste zugreifen.\n", + "```python\n", + "liste[start:stop:step]\n", + "```\n", + "* _start_ gibt den Index an, an dem unser Teil der Liste startet\n", + "* _stop_ gibt den Index an, bis zu dem unser Teil der Liste geht. Das Element mit diesem Index ist jedoch nicht enthalten.\n", + "* _step_ gibt die Schrittweite zwischen zwei Indices unserer Teilliste an" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[True, 4.2, 'foo', False, 'spam', 'egg']\n", + "[0, 4.2, False]\n", + "[42, 'egg', 'spam', False, 'foo', 4.2, True]\n" + ] + } + ], + "source": [ + "liste = [0, True, 4.2, \"foo\", False, \"spam\", \"egg\", 42]\n", + "print(liste[1:-1]) # von Index 1 bis Index -1\n", + "print(liste[0:6:2]) # von Index 0 bis Index 6 jedes zweite Element\n", + "print(liste[-1:0:-1]) # von Index -1 bis Index 0 jedes Element" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_start_, _stop_ und _step_ können allerdings auch weggelassen werden.\n", + "* Wird _start_ weggelassen startet die Teilliste mit dem ersten Element.\n", + "* Wird _stop_ weggelassen, endet die Teilliste mit dem letzten Element.\n", + "* wird _step_ weggelassen, ist die Schrittweite 1" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[4.2, False, 'egg']\n", + "[0, 'foo', 'egg']\n", + "[0, False]\n", + "[True, 4.2, 'foo', False, 'spam', 'egg', 42]\n" + ] + } + ], + "source": [ + "liste = [0, True, 4.2, \"foo\", False, \"spam\", \"egg\", 42]\n", + "print(liste[2::2]) # von Index 2 bis zum Ende jedes zweite Element\n", + "print(liste[:-1:3]) # vom Start bis Index -1 jedes dritte Element\n", + "print(liste[::4]) # vom Start bis zum Ende jedes vierte Element\n", + "print(liste[1:]) # von Index 1 bis zum Ende" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Elemente hinzufügen\n", + "Nachdem wir eine Liste erstellt haben, möchten gegebenenfalls auch Elemente hinzufügen. Dazu gibt es mehrere Möglichkeiten. Wir können mit Hilfe der `list.append()` Methode ein Element an unsere Liste hinten anhängen oder mit der `list.insert()` Methode ein Element an einem Index in unsere Liste einfügen, wobei die Elemente nach diesem Index nach hinten aufrücken." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, True, 4.2, 'foo', False, 'spam', 'egg', 42]\n", + "[0, True, 4.2, 'foo', False, 'spam', 'egg', 42, 3.14]\n" + ] + } + ], + "source": [ + "liste = [0, True, 4.2, \"foo\", False, \"spam\", \"egg\", 42]\n", + "print(liste)\n", + "liste.append(3.14)\n", + "print(liste)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, True, 4.2, 'foo', False, 'spam', 'egg', 42]\n", + "[0, True, 4.2, 'foo', 'test', False, 'spam', 'egg', 42]\n" + ] + } + ], + "source": [ + "liste = [0, True, 4.2, \"foo\", False, \"spam\", \"egg\", 42]\n", + "print(liste)\n", + "liste.insert(4, \"test\")\n", + "print(liste)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Elemente finden\n", + "Eventuell wollen wir wissen ob ein Element in unserer Liste enthalten ist, und wenn es in unserer Liste enthalten ist, wollen wir eventuell wissen an welcher Stelle oder wie oft.\n", + "\n", + "Zuerst wollen wir lernen, wie wir mit dem Schlüsselwort `in` feststellen, ob ein Element in unserer Liste enthalten ist:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "egg: True\n", + "ham: False\n" + ] + } + ], + "source": [ + "liste = [0, True, 4.2, False, \"spam\", \"egg\", 42]\n", + "print(\"egg:\", \"egg\" in liste)\n", + "print(\"ham:\", \"ham\" in liste)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Aber vorsicht:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1: True\n" + ] + } + ], + "source": [ + "liste = [0, True, 4.2, False, \"spam\", \"egg\", 42]\n", + "print(\"1:\", 1 in liste)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Scheinbar ist der integer `1` in der Liste enthalten, obwohl keiner der Einträge auf den ersten Blick danach aussieht. Also wird ein Element unserer Liste als `1` interpretiert oder ist `== 1`. Um rauszufinden an welcher Stelle sich dieses Element befindet können wir die `list.index()` Methode benutzen. Dabei müssen wir allerdings vorsichtig sein, versuchen wir nämlich den Index eines Elementes zu finden, der __nicht__ in der Liste enthalten ist, erhalten wir einen Fehler." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1: True\n", + "True\n" + ] + } + ], + "source": [ + "liste = [0, True, 4.2, False, \"spam\", \"egg\", 42]\n", + "print(\"1:\", 1 in liste)\n", + "ind = liste.index(1)\n", + "print(liste[ind])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " Der boolean `True` auf dem Index `1` wird hier also als `1` erkannt. Dieses Phänomen tritt allerdings nur mit `1` und `True` und `0` und `False` auf. Um dieses Problem zu umgehen nutzen wir im folgenden eine Liste mit anderen Elementen." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a']\n", + "Erstes Auftreten von 'a': 0\n", + "Erstes Auftreten von 'b': 1\n", + "Erstes Auftreten von 'c': 4\n", + "Erstes Auftreten von 'd': 6\n" + ] + } + ], + "source": [ + "liste = list(\"abracadabra\")\n", + "print(liste)\n", + "print(\"Erstes Auftreten von 'a':\", liste.index(\"a\"))\n", + "print(\"Erstes Auftreten von 'b':\", liste.index(\"b\"))\n", + "print(\"Erstes Auftreten von 'c':\", liste.index(\"c\"))\n", + "print(\"Erstes Auftreten von 'd':\", liste.index(\"d\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wie wir sehen können zeigt und `list.index()` lediglich das erste Auftreten eines Elementes an, auch wenn dieses Element mehrfach in der Liste auftaucht.\n", + "\n", + "Um rauszufinden wie häufig ein Element in unserer Liste auftaucht können wir die `list.count()` Methode benutzen." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Anzahl von 'a': 5\n", + "Anzahl von 'b': 2\n", + "Anzahl von 'c': 1\n", + "Anzahl von 'd': 1\n", + "Anzahl von 'e': 0\n" + ] + } + ], + "source": [ + "liste = ['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a']\n", + "print(\"Anzahl von 'a':\", liste.count(\"a\"))\n", + "print(\"Anzahl von 'b':\", liste.count(\"b\"))\n", + "print(\"Anzahl von 'c':\", liste.count(\"c\"))\n", + "print(\"Anzahl von 'd':\", liste.count(\"d\"))\n", + "print(\"Anzahl von 'e':\", liste.count(\"e\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dabei sehen wir auch, dass uns die `list.count()` Methode keinen Fehler gibt, wenn ein Element (im obigen Fall 'e') nicht in der Liste enthalten ist, sondern `0` zurück gibt." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Elemente entfernen\n", + "Wenn wir Elemente entfernen wollen, haben wir auch wieder mehrere Möglichkeiten, die sich im Wesentlichen in unserer Herangehungsweise entscheiden. Kennen wir den Index des Elementes, welches wir aus der Liste entfernen möchten, können wir das Schlüsselwort `del` oder die `list.pop()` Methode verwenden, kennen wir jedoch das Element, das wir entfernen möchten, benutzen wir die `list.remove()` Methode." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['foo', 'test', 23, 'spam', 'egg', 42]\n", + "['test', 23, 'spam', 'egg', 42]\n" + ] + } + ], + "source": [ + "liste = [\"foo\", \"test\", 23, \"spam\", \"egg\", 42]\n", + "print(liste)\n", + "del liste[0]\n", + "print(liste)\n", + "# del liste\n", + "# print(liste)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wie wir sehen, können wir nicht nur einzelne Elemente einer Liste anhand ihres Indexes, sondern auch die gesamte Liste entfernen. Das Schlüsselwort `del` entfernt die Referenz einer Variable und somit die Variable, weshalb wir auch einen `NameError` erhalten, wenn wir versuchen die Variable zu benutzen, nachdem wir sie gelöscht haben." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['foo', 'test', 23, 'spam', 'egg', 42]\n", + "['foo', 'test', 23, 'spam', 'egg']\n", + "Entfernt: 42\n" + ] + } + ], + "source": [ + "liste = [\"foo\", \"test\", 23, \"spam\", \"egg\", 42]\n", + "print(liste)\n", + "element = liste.pop()\n", + "print(liste)\n", + "print(\"Entfernt:\", element)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Oben haben wir statt des `del` Schlüsselwortes die `list.pop()` Methode benutzt. Das hat den Vorteil, dass uns die `list.pop()` Methode das Element, welches wir aus der Liste entfernt haben, zurück gibt. Wenn wir der `list.pop()` keinen Index mitgeben, entfernt sie standardmäßig das letzte Element. Wenn wir der `list.pop()` Methode einen Index geben, entfernt sie das Element an diesem Index aus der Liste." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['foo', 'test', 23, 'spam', 'egg', 42]\n", + "['foo', 'test', 23, 'egg', 42]\n", + "Entfernt: spam\n" + ] + } + ], + "source": [ + "liste = [\"foo\", \"test\", 23, \"spam\", \"egg\", 42]\n", + "print(liste)\n", + "element = liste.pop(3)\n", + "print(liste)\n", + "print(\"Entfernt:\", element)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nun wollen wir ein Element, dessen Wert wir kennen aus der Liste entfernen. Dazu benutzen wir die `list.remove()` Methode. Diese entfernt das erste Auftreten des Wertes, den wir ihr geben, aus der Liste." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a']\n", + "['b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a']\n", + "['b', 'r', 'c', 'a', 'd', 'a', 'b', 'r', 'a']\n" + ] + } + ], + "source": [ + "liste = list(\"abracadabra\")\n", + "print(liste)\n", + "liste.remove(\"a\")\n", + "print(liste)\n", + "liste.remove(\"a\")\n", + "print(liste)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Verschachtelung\n", + "Da wir in einer Liste Elemente beliebigen Typs speichern können, können wir auch eine Liste als Element einer Liste speichern. Auf die innere Liste können wir dann genauso zugreifen, wie auf jedes andere Element." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[0, 1, 2], [3, 4, 5]]\n", + "Länge outer_list: 2\n", + "outer_list[0]: [0, 1, 2]\n", + "outer_list[1]: [3, 4, 5]\n" + ] + } + ], + "source": [ + "inner_list1 = [0, 1, 2]\n", + "inner_list2 = [3, 4, 5]\n", + "outer_list = [inner_list1, inner_list2]\n", + "print(outer_list)\n", + "print(\"Länge outer_list:\", len(outer_list))\n", + "print(\"outer_list[0]:\", outer_list[0])\n", + "print(\"outer_list[1]:\", outer_list[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Die äußere Liste enthält zwei Elemente, die in diesem Fall jeweils Listen sind." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Erstes Element von:\n", + "outer_list[0]: 0\n", + "outer_list[1]: 3\n" + ] + } + ], + "source": [ + "inner_list1 = [0, 1, 2]\n", + "inner_list2 = [3, 4, 5]\n", + "outer_list = [inner_list1, inner_list2]\n", + "# die jeweils ersten Elemente der inneren Listen:\n", + "print(\"Erstes Element von:\")\n", + "print(\"outer_list[0]:\", outer_list[0][0])\n", + "print(\"outer_list[1]:\", outer_list[1][0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Die vergessenen Methoden\n", + "Wenn wir uns mit der `dir()` Funktion die Methoden eines `list` Objektes ansehen und alle Einträge mit `__` am Anfang und Ende des Namens ignorieren, stellen wir fest, dass wir noch einige Methoden nicht behandelt haben." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['__add__',\n", + " '__class__',\n", + " '__contains__',\n", + " '__delattr__',\n", + " '__delitem__',\n", + " '__dir__',\n", + " '__doc__',\n", + " '__eq__',\n", + " '__format__',\n", + " '__ge__',\n", + " '__getattribute__',\n", + " '__getitem__',\n", + " '__gt__',\n", + " '__hash__',\n", + " '__iadd__',\n", + " '__imul__',\n", + " '__init__',\n", + " '__init_subclass__',\n", + " '__iter__',\n", + " '__le__',\n", + " '__len__',\n", + " '__lt__',\n", + " '__mul__',\n", + " '__ne__',\n", + " '__new__',\n", + " '__reduce__',\n", + " '__reduce_ex__',\n", + " '__repr__',\n", + " '__reversed__',\n", + " '__rmul__',\n", + " '__setattr__',\n", + " '__setitem__',\n", + " '__sizeof__',\n", + " '__str__',\n", + " '__subclasshook__',\n", + " 'append',\n", + " 'clear',\n", + " 'copy',\n", + " 'count',\n", + " 'extend',\n", + " 'index',\n", + " 'insert',\n", + " 'pop',\n", + " 'remove',\n", + " 'reverse',\n", + " 'sort']" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dir(list)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Da uns die `dir()` Funktion eine Liste zurückgibt, können wir uns diese Methoden ausgeben lassen, indem wir die letzten 11 Elemente anzeigen:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['append',\n", + " 'clear',\n", + " 'copy',\n", + " 'count',\n", + " 'extend',\n", + " 'index',\n", + " 'insert',\n", + " 'pop',\n", + " 'remove',\n", + " 'reverse',\n", + " 'sort']" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dir(list)[-11:]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### list.clear()\n", + "Die `list.clear()` Methode können wir benutzen um alle Elemente einer Liste zu entfernen. Der Anwendungsfall ist relativ begrenzt, da wir auch einfach eine leere Liste erstellen können." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n" + ] + } + ], + "source": [ + "liste = list(\"abracadabra\")\n", + "liste.clear()\n", + "print(liste)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n" + ] + } + ], + "source": [ + "# Alternativ:\n", + "liste = list(\"abracadabra\")\n", + "liste = list()\n", + "print(liste)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### list.copy()\n", + "Die `list.copy()` Methode kann benutzt werden um eine Kopie der Liste zu erstellen. Auch hier gibt es eine alternative Möglichkeit über Slicing, dasselbe zu erreichen." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a']\n", + "['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a']\n" + ] + } + ], + "source": [ + "liste = list(\"abracadabra\")\n", + "liste_copy = liste.copy()\n", + "print(liste)\n", + "print(liste_copy)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a']\n", + "['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a']\n" + ] + } + ], + "source": [ + "# Alternativ:\n", + "liste = list(\"abracadabra\")\n", + "liste_copy = liste[:]\n", + "print(liste)\n", + "print(liste_copy)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### list.extend()\n", + "Die `list.extend()` Methode kann benutzt werden um an die bestehende Liste eine andere Liste anzuhängen." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a', 's', 'i', 'm', 's', 'a', 'l', 'a']\n" + ] + } + ], + "source": [ + "liste = list(\"abracadabra\")\n", + "liste.extend(\"simsala\")\n", + "print(liste)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a', 's', 'i', 'm', 's', 'a', 'l', 'a']\n" + ] + } + ], + "source": [ + "# Alternativ:\n", + "liste = list(\"abracadabra\")\n", + "liste = liste + list(\"simsala\")\n", + "print(liste)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### list.reverse()\n", + "Mit der `list.reverse()` können wir eine Liste umdrehen. Wie auch die voherigen Methoden gibt es auch hier Alternativen." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['a', 'r', 'b', 'a', 'd', 'a', 'c', 'a', 'r', 'b', 'a']\n" + ] + } + ], + "source": [ + "liste = list(\"abracadabra\")\n", + "liste.reverse()\n", + "print(liste)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['a', 'r', 'b', 'a', 'd', 'a', 'c', 'a', 'r', 'b', 'a']\n" + ] + } + ], + "source": [ + "# Alternativ:\n", + "liste = list(\"abracadabra\")\n", + "liste = liste[::-1]\n", + "print(liste)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### list.sort()\n", + "Mit `list.sort()` lässt sich eine Liste sortieren, solange die Elemente miteinander vergleichbar sind." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['a', 'a', 'a', 'a', 'a', 'b', 'b', 'c', 'd', 'r', 'r']\n" + ] + } + ], + "source": [ + "liste = list(\"abracadabra\")\n", + "liste.sort()\n", + "print(liste)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## tuple\n", + "Ein tuple ist grob gesagt eine unveränderliche Liste. Ein Tupel hat eine Länge, Elemente können nicht entfernt oder hinzugefügt werden. Lediglich die Elemente eines Tupels lassen sich ändern, wenn sie veränderlich sind." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a')\n", + "(2, 3, 23, 42)\n", + "(3, 2, 3)\n" + ] + } + ], + "source": [ + "t1 = tuple(\"abracadabra\")\n", + "t2 = (2,3,23,42)\n", + "t3 = 3,2,3\n", + "print(t1)\n", + "print(t2)\n", + "print(t3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Ein Tuple lässt sich über die `tuple()` Funktion oder über runde Klammern `()` definieren. Die runden Klammern können wir allerdings meistens weglassen. Der Zugriff auf die Elemente funktioniert, wie bei Listen sowohl über den Index, als auch über Slicing." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "c\n", + "('a', 'b', 'r', 'a', 'c')\n" + ] + } + ], + "source": [ + "Tuple = tuple(\"abracadabra\")\n", + "print(Tuple[4])\n", + "print(Tuple[0:5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wenn wir uns die Methoden von einem Tuple anschauen, stellen wir fest, dass es nur zwei \"normale\" Methoden gibt, die wir auch schon von der Liste kennen, nämlich `tuple.count()` und `tuple.index()`. Desweiteren können wir auf einen Tuple auch die `len()` Funktion und das Schlüsselwort `in` anwenden." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['__add__',\n", + " '__class__',\n", + " '__contains__',\n", + " '__delattr__',\n", + " '__dir__',\n", + " '__doc__',\n", + " '__eq__',\n", + " '__format__',\n", + " '__ge__',\n", + " '__getattribute__',\n", + " '__getitem__',\n", + " '__getnewargs__',\n", + " '__gt__',\n", + " '__hash__',\n", + " '__init__',\n", + " '__init_subclass__',\n", + " '__iter__',\n", + " '__le__',\n", + " '__len__',\n", + " '__lt__',\n", + " '__mul__',\n", + " '__ne__',\n", + " '__new__',\n", + " '__reduce__',\n", + " '__reduce_ex__',\n", + " '__repr__',\n", + " '__rmul__',\n", + " '__setattr__',\n", + " '__sizeof__',\n", + " '__str__',\n", + " '__subclasshook__',\n", + " 'count',\n", + " 'index']" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dir(tuple)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a')\n", + "Länge: 11\n", + "Anzahl 'a': 5\n", + "Erstes 'b': 1\n", + "e? False\n" + ] + } + ], + "source": [ + "Tuple = tuple(\"abracadabra\")\n", + "print(Tuple)\n", + "print(\"Länge:\", len(Tuple))\n", + "print(\"Anzahl 'a':\", Tuple.count(\"a\"))\n", + "print(\"Erstes 'b':\", Tuple.index(\"b\"))\n", + "print(\"e?\", \"e\" in Tuple)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wir können Tuple auch benutzen um den Wert zweier Variablen zu tauschen. Bisher würden wir dafür den Wert einer Variable in einer temporären Variable (`tmp`) speichern und die Werte so tauschen." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a: 10\n", + "b: 5\n" + ] + } + ], + "source": [ + "a = 5\n", + "b = 10\n", + "tmp = a\n", + "a = b\n", + "b = tmp\n", + "print(\"a:\", a)\n", + "print(\"b:\", b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Durch die Verwendung von Tuplen können wir nun auf unsere temporäre Variable verzichten und den Code lesbarer gestalten:" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a: 10\n", + "b: 5\n" + ] + } + ], + "source": [ + "a = 5\n", + "b = 10\n", + "a, b = b, a\n", + "# Alternativ: (a, b) = (b, a)\n", + "print(\"a:\", a)\n", + "print(\"b:\", b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Strings\n", + "Jetzt da wir Listen und Tuple kennengelernt haben lohnt es sich, nochmal Strings anzuschauen, da wir auch hier auch auf einzelne Zeichen mit dem Index zugreifen können. So wie bei Listen und Tupeln, können wir auch bei Strings die `str.count()` und `str.index()` Methoden verwenden." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a\n", + "a\n", + "abra\n" + ] + } + ], + "source": [ + "zauberwort = \"abracadabra\"\n", + "print(zauberwort[0])\n", + "print(zauberwort[-1])\n", + "teilwort = zauberwort[:4]\n", + "print(teilwort)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "zauberwort = \"abracadabra\"\n", + "zauberwort.count(\"a\")" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n" + ] + } + ], + "source": [ + "zauberwort = \"abracadabra\"\n", + "print(zauberwort.index(\"b\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "e? False\n" + ] + } + ], + "source": [ + "zauberwort = \"abracadabra\"\n", + "print(\"e?\", \"e\" in zauberwort)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## dict\n", + "Ein Dictionary speichert Werte nicht anhand ihres Indexes, sondern anhand eines Schlüssels.\n", + "### Erstellen eines dict\n", + "Ein leeres Dictionary kann auf zwei Arten erstellt werden:" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "leer1 = dict()\n", + "leer2 = {}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Möchten wir ein Dictionary mit Einträgen erstellen, können wir dies entweder durch die `dict()` Funktion erreichen, in der wir Schlüssel und Werte als Liste von Tuplen mit zwei Elementen übergeben, oder indem wir Schlüssel und Werte durch Doppelpunkte `:` getrennt in geschweiften Klammern `{}` als Literale definieren." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'name': 'Max', 'nachname': 'Mustermann', 'alter': 42}\n", + "{'name': 'Martha', 'nachname': 'Musterfrau', 'alter': 23}\n" + ] + } + ], + "source": [ + "dict1 = {\"name\": \"Max\", \"nachname\": \"Mustermann\", \"alter\": 42}\n", + "dict2 = dict([(\"name\", \"Martha\"), (\"nachname\", \"Musterfrau\"), (\"alter\", 23)])\n", + "print(dict1)\n", + "print(dict2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Als Schlüssel sind Werte aller unveränderlichen Typen erlaubt, in einem Dictionary müssen die Schlüssel auch nicht denselben Typen haben, es ergibt sich meistens aber, dass die Schlüssel denselben Typen haben." + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{0: 'integer', True: 'boolean', (0, 0): 'tuple', 's': 'strings'}\n" + ] + } + ], + "source": [ + "beispiel_dict = {0:\"integer\", True:\"boolean\", (0,0):\"tuple\", \"s\":\"strings\"}\n", + "print(beispiel_dict)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Zugriff\n", + "Der Zugriff auf die Elemente erfolgt dann über den entsprechenden Schlüssel:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Alter:\n", + "Max: 42\n", + "Martha: 23\n" + ] + } + ], + "source": [ + "Max = {\"name\": \"Max\", \"nachname\": \"Mustermann\", \"alter\": 42}\n", + "Martha = {\"name\": \"Martha\", \"nachname\": \"Musterfrau\", \"alter\": 23}\n", + "print(\"Alter:\")\n", + "print(\"Max:\", Max[\"alter\"])\n", + "print(\"Martha:\", Martha[\"alter\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Löschen erfolgt ähnlich:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'name': 'Max', 'alter': 42}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "del Max[\"nachname\"]\n", + "Max" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Alternativ kann für den Zugriff die `dict.get()` Methode benutzt werden. Diese ermöglicht es auch einen Standardwert anzugeben, wenn der Schlüssel in dem Dictionary nicht vorhanden ist." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Alter:\n", + "Max: 42\n", + "Martha: 0\n" + ] + } + ], + "source": [ + "Max = {\"name\": \"Max\", \"nachname\": \"Mustermann\", \"alter\": 42}\n", + "Martha = {\"name\": \"Martha\", \"nachname\": \"Musterfrau\"}\n", + "print(\"Alter:\")\n", + "print(\"Max:\", Max.get(\"alter\", 0))\n", + "print(\"Martha:\", Martha.get(\"alter\", 0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Den Wert zu einem Schlüssel können wir setzen indem wir einem Schlüssel einen Wert zuweisen, existiert dieser Schlüssel bereits, wird sein Wert überschrieben." + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'name': 'Martha', 'nachname': 'Musterfrau', 'alter': 23}\n" + ] + } + ], + "source": [ + "Max = {\"name\": \"Max\", \"nachname\": \"Mustermann\", \"alter\": 42}\n", + "Martha = {\"name\": \"Martha\", \"nachname\": \"Musterfrau\"}\n", + "Martha[\"alter\"] = 23\n", + "print(Martha)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Natürlich kann man auch das `in` Schlüsselwort mit Dictionaries benutzen:" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "name? True\n", + "alter? False\n" + ] + } + ], + "source": [ + "Martha = {\"name\": \"Martha\", \"nachname\": \"Musterfrau\"}\n", + "print(\"name?\", \"name\" in Martha)\n", + "print(\"alter?\", \"alter\" in Martha)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Die `len()` Funktion liefert bei einem Dictionary die Anzahl an Schlüsseln wieder:" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Anzahl Schlüssel: 2\n" + ] + } + ], + "source": [ + "Martha = {\"name\": \"Martha\", \"nachname\": \"Musterfrau\"}\n", + "print(\"Anzahl Schlüssel:\", len(Martha))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### items(), keys() und values()\n", + "Die drei Methoden `dict.items()`, `dict.keys()` und `dict.values()` sind sich relativ ähnlich, weshalb wir sie zusammen betrachten wollen." + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dict_keys([0, True, (0, 0), 's'])\n", + "dict_values(['integer', 'boolean', 'tuple', 'strings'])\n", + "dict_items([(0, 'integer'), (True, 'boolean'), ((0, 0), 'tuple'), ('s', 'strings')])\n" + ] + } + ], + "source": [ + "dictionary = {0:\"integer\", True:\"boolean\", (0,0):\"tuple\", \"s\":\"strings\"}\n", + "print(dictionary.keys()) # liefert die Schlüssel als Liste\n", + "print(dictionary.values()) # liefert die Werte als Liste\n", + "print(dictionary.items()) # liefert Schlüssel und Werte als Tuple in einer Liste" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### pop()\n", + "Auch Dictionaries besitzen eine `dict.pop()` Methode." + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{True: 'boolean', (0, 0): 'tuple', 's': 'strings'}\n" + ] + } + ], + "source": [ + "dictionary = {0:\"integer\", True:\"boolean\", (0,0):\"tuple\", \"s\":\"strings\"}\n", + "value = dictionary.pop(0)\n", + "print(dictionary)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wie wir sehen funktioniert die `dict.pop()` Methode ähnlich, wie bei den Listen. Der Wert mit dem angegebenen Schlüssel wird zurückgegeben und aus dem Dictionary entfernt." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Die for-Schleife\n", + "Die for-Schleife kann benutzt werden um über verschiedene Objekte zu iterieren. Dabei ist die Syntax einer for-Schleife die folgende:\n", + "```python\n", + "for variable in objekt:\n", + " Befehle\n", + "```\n", + "* _objekt_ ist dabei das Objekt, über das wir iterieren.\n", + "* _variable_ enthält jeweils ein Element aus dem Objekt.\n", + "\n", + "Wir kennen bereits Listen, Tuple, Dictionaries und Strings, über jeden dieser Typen können wir iterieren." + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a\n", + "b\n", + "r\n", + "a\n", + "c\n", + "a\n", + "d\n", + "a\n", + "b\n", + "r\n", + "a\n" + ] + } + ], + "source": [ + "# Iteration über einen string:\n", + "zauberwort = \"abracadabra\"\n", + "for zeichen in zauberwort:\n", + " print(zeichen)" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "True\n", + "foo\n", + "42\n" + ] + } + ], + "source": [ + "# Iteration über eine Liste:\n", + "liste = [0, True, \"foo\", 42]\n", + "for element in liste:\n", + " print(element)" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "# Iteration über einen Tuple:\n", + "Tuple = (1,2,3)\n", + "for zahl in Tuple:\n", + " print(zahl)" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "name : Max\n", + "nachname : Mustermann\n", + "alter : 42\n" + ] + } + ], + "source": [ + "# Iteration über ein Dictionary:\n", + "Max = {\"name\": \"Max\", \"nachname\": \"Mustermann\", \"alter\": 42}\n", + "for attribut in Max:\n", + " print(attribut, \":\", Max[attribut])" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "name : Max\n", + "nachname : Mustermann\n", + "alter : 42\n" + ] + } + ], + "source": [ + "# Alternativ:\n", + "Max = {\"name\": \"Max\", \"nachname\": \"Mustermann\", \"alter\": 42}\n", + "for attribut, wert in Max.items():\n", + " print(attribut, \":\", wert)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### range()\n", + "Die `range()` Funktion ist in vielerlei Hinsicht praktisch. Sie ermöglicht es uns auf einfache, gut lesbare Art und Weise Zahlenfolgen zu erzeugen. Warum das so praktisch ist werden wir gleich sehen.\n", + "```python\n", + "range(stop)\n", + "range(start, stop[, step])\n", + "```\n", + "Wir können `range()` entweder nur mit einem _stop_ Wert aufrufen (dieser muss ein integer sein), oder mit einem _start_, einem _stop_ und einen optionalen _step_ Wert. Bei beiden Varianten erhalten wir ein `range` Objekt.\n", + "Diese verhalten sich ähnlich wie die Werte beim Slicing. Geben wir keinen Wert für `start` an startet unser `range` Objekt bei `0`, geben wir keinen Wert für `step` an, ist die Schrittweite `1`." + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n" + ] + } + ], + "source": [ + "# alle Zahlen von 0 bis 10:\n", + "r = range(10)\n", + "print(list(r))" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40]\n" + ] + } + ], + "source": [ + "# jede zweite Zahl von 2 bis 42:\n", + "r = range(2, 42, 2)\n", + "print(list(r))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Genauso, wie beim Slicing können die Werte auch negativ sein." + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, -2, -4, -6, -8, -10, -12, -14, -16, -18, -20, -22, -24, -26, -28, -30, -32, -34, -36, -38, -40, -42, -44, -46, -48, -50, -52, -54, -56, -58, -60, -62, -64, -66, -68, -70, -72, -74, -76, -78, -80, -82, -84, -86, -88, -90, -92, -94, -96, -98]\n" + ] + } + ], + "source": [ + "# von 0 bis -100 jede zweite Zahl:\n", + "r = range(0, -100, -2)\n", + "print(list(r))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Ein range Objekt kann auch benutzt werden um sehr große Zahlenreihen zu erzeugen, da die Zahlen erst berechnet werden, wenn sie benötigt werden." + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "range(0, 10000000000000000)\n" + ] + } + ], + "source": [ + "r = range(10000000000000000)\n", + "print(r)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dadurch, dass wir über ein `range` Objekt iterieren können, können wir `range()` gut in einer for-Schleife benutzen." + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n", + "5\n", + "6\n", + "7\n", + "8\n", + "9\n" + ] + } + ], + "source": [ + "for i in range(10):\n", + " print(i)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### break, continue und else\n", + "Die Schlüsselwörter `break`, `continue` und `else` können wir innerhalb einer for-Schleife genauso benutzen, wie in einer while-Schleife." + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "brcdbr\n" + ] + } + ], + "source": [ + "zauberwort = \"abracadabra#test\"\n", + "neuer_zauber = \"\"\n", + "for zeichen in zauberwort:\n", + " if zeichen == \"#\":\n", + " break\n", + " elif zeichen == \"a\":\n", + " continue\n", + " else:\n", + " neuer_zauber += zeichen\n", + "print(neuer_zauber)" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Kein 'Y' gefunden.\n" + ] + } + ], + "source": [ + "string = \"Das ist ein Teststring.\"\n", + "for zeichen in string:\n", + " if zeichen == \"Y\":\n", + " break\n", + "else:\n", + " print(\"Kein 'Y' gefunden.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "for-Schleifen können verschachtelt werden, was wir benutzen können um über ein verschachteltes Objekt zu iterieren." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "test\n", + "foo\n", + "bar\n", + "ham\n", + "spam\n", + "egg\n" + ] + } + ], + "source": [ + "table = [\n", + " [\n", + " \"test\",\n", + " \"foo\",\n", + " \"bar\"\n", + " ],\n", + " [\n", + " \"ham\",\n", + " \"spam\",\n", + " \"egg\"\n", + " ]\n", + "]\n", + "for row in table:\n", + " for entry in row:\n", + " print(entry)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## sets\n", + "Sets sind Mengen im mathematischen Sinn. Das bedeutet ein Element kann entweder in einer Menge enthalten sein, oder eben nicht.\n", + "### Erstellen eines set\n", + "Ein Set kann entweder über die `set()` Funktion aus einem anderen Objekt erzeugt werden, oder über geschweifte Klammern `{}` welche die Literale eines Sets bilden." + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "set()\n" + ] + } + ], + "source": [ + "Set = set()\n", + "print(Set)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{2, 3, 5, 7}\n" + ] + } + ], + "source": [ + "Set = {2,3,5,7}\n", + "print(Set)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### in und len()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n" + ] + } + ], + "source": [ + "some_primes = {2, 3, 5, 7, 11, 13}\n", + "print(12 in some_primes)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n" + ] + } + ], + "source": [ + "some_primes = {2, 3, 5, 7, 11, 13}\n", + "print(len(some_primes))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Elemente hinzufügen\n", + "Nach dem wir eine Menge erstellt haben, können wir mit der `set.add()` Methode Elemente hinzufügen." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{2, 3, 5, 7, 11, 13, 17}\n" + ] + } + ], + "source": [ + "some_primes = {2, 3, 5, 7, 11, 13}\n", + "some_primes.add(17)\n", + "print(some_primes)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Um nicht nur einzelne Elemente, sondern mehrere Elemente an eine Menge anzuhängen, können wir die `set.update()` Methode benutzen." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{2, 3, 5, 7, 11, 13, 17, 19, 23}\n" + ] + } + ], + "source": [ + "some_primes = {2, 3, 5, 7, 11, 13}\n", + "more_primes = [17, 19, 23]\n", + "some_primes.update(more_primes)\n", + "print(some_primes)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Elemente entfernen\n", + "Um Elemente zu entfernen gibt es zwei Möglichkeiten. Die `set.pop()` Methode entfernt ein Element aus der Menge und gibt es dabei zurück. Die `set.remove()` Methode kann dafür benutzt werden, um Elemente anhand ihres Wertes aus der Menge zu entfernen." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1, 2)\n", + "{'test', 42, 'foo', 23}\n" + ] + } + ], + "source": [ + "Set = {23, \"foo\", 42, \"test\", (1,2)}\n", + "element = Set.pop()\n", + "print(element)\n", + "print(Set)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{(1, 2), 'test', 42, 23}\n" + ] + } + ], + "source": [ + "Set = {23, \"foo\", 42, \"test\", (1,2)}\n", + "Set.remove(\"foo\")\n", + "print(Set)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Mengenoperationen\n", + "Set-Objekte bieten Mengenoperationen an, die auch aus der Mathematik bekannt sind. Diese sind die Schnittmenge, die Vereinigungsmenge und die Differenzmenge.\n", + "\n", + "Die Schnittmenge enthält alle Elemente, die in beiden Mengen enthalten sind." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{1, 3, 5}\n" + ] + } + ], + "source": [ + "# Schnittmenge zweier Mengen:\n", + "set1 = {1, 3, 4, 5, 2}\n", + "set2 = {5, 8, 1, 3, 7, 9}\n", + "schnittmenge = set1 & set2\n", + "print(schnittmenge)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Alternativ können wir auch die `set.intersection()` Methode benutzen." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{1, 3, 5}\n" + ] + } + ], + "source": [ + "# Schnittmenge zweier Mengen:\n", + "set1 = {1, 3, 4, 5, 2}\n", + "set2 = {5, 8, 1, 3, 7, 9}\n", + "schnittmenge = set1.intersection(set2)\n", + "print(schnittmenge)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Die Vereinigungsmenge enthält alle Elemente, die in einer der Mengen enthalten sind." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{1, 2, 3, 4, 5, 7, 8, 9}\n" + ] + } + ], + "source": [ + "# Vereinigungsmenge zweier Mengen:\n", + "set1 = {1, 3, 4, 5, 2}\n", + "set2 = {5, 8, 1, 3, 7, 9}\n", + "vereinigung = set1 | set2\n", + "print(vereinigung)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Alternativ können wir auch die `set.union()` Methode benutzen." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{1, 2, 3, 4, 5, 7, 8, 9}\n" + ] + } + ], + "source": [ + "# Vereinigungsmenge zweier Mengen:\n", + "set1 = {1, 3, 4, 5, 2}\n", + "set2 = {5, 8, 1, 3, 7, 9}\n", + "vereinigung = set1.union(set2)\n", + "print(vereinigung)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Die Differenzmenge einer Menge S1 mit einer Menge S2 enthält alle Elemente, die in der Menge S1 aber nicht in der Menge S2 sind." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{1, 2, 3}\n" + ] + } + ], + "source": [ + "s1 = {1, 3, 4, 5, 2}\n", + "s2 = {4, 5}\n", + "differenz = s1 - s2\n", + "print(differenz)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Alternativ können wir auch die `set.difference()` Methode benutzen." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{1, 2, 3}\n" + ] + } + ], + "source": [ + "s1 = {1, 3, 4, 5, 2}\n", + "s2 = {4, 5}\n", + "differenz = s1.difference(s2)\n", + "print(differenz)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Es gibt auch noch die symmetrische Differenzmenge zweier Mengen. Diese enthält alle Elemente, die in einer der beiden Mengen, aber nicht in beiden Mengen enthalten sind." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{1, 2, 3, 6}\n" + ] + } + ], + "source": [ + "s1 = {1, 3, 4, 5, 2}\n", + "s2 = {4, 5, 6}\n", + "sym_differenz = s1 ^ s2\n", + "print(sym_differenz)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Alternativ können wir für die symmetrische Differenz auch die `set.symmetric_difference()` Methode benutzen." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{1, 2, 3, 6}\n" + ] + } + ], + "source": [ + "s1 = {1, 3, 4, 5, 2}\n", + "s2 = {4, 5, 6}\n", + "sym_differenz = s1.symmetric_difference(s2)\n", + "print(sym_differenz)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Mit der `set.isdisjoint()` Methode können wir testen ob zwei Mengen disjunkt sind. Zwei Mengen sind disjunkt, wenn ihre Schnittmenge leer ist." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "s1 = {1, 3, 4, 5, 2}\n", + "s2 = {4, 5, 6}\n", + "s3 = {7, 8, 2}\n", + "print(s1.isdisjoint(s2))\n", + "print(s2.isdisjoint(s3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Mit der `set.issubset()` und der `set.issuperset()` Methode können wir feststellen, ob eine Menge eine Teilmenge, beziehungsweise eine Obermenge einer anderen Menge ist. Eine Menge _s1_ ist Teilmenge einer Menge _s2_, wenn alle Elemente von _s1_ in der Menge _s2_ enthalten sind. _s2_ ist dann die Obermenge von s1." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ist s2 eine Teilmenge von s1:\n", + "True\n", + "Ist s1 eine Obermenge von s2:\n", + "True\n" + ] + } + ], + "source": [ + "s1 = {1, 2, 3, 4, 5}\n", + "s2 = {1, 2}\n", + "print(\"Ist s2 eine Teilmenge von s1:\")\n", + "print(s2.issubset(s1))\n", + "print(\"Ist s1 eine Obermenge von s2:\")\n", + "print(s1.issuperset(s2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Statt der `set.issubset()` Methode können wir auch den `<=` Operator benutzen, statt der `set.issuperset()` Methode können wir auch den `>=` Operator benutzen.\n", + "\n", + "Den `>` Operator können wir benutzen um zu ermitteln, ob eine Menge _s1_ eine _echte_ Obermenge von einer Menge _s2_ ist. Dies ist der Fall, wenn _s1_ eine Obermenge von _s2_ und nicht die gleiche Menge ist.\n", + "\n", + "Den `<` Operator können wir benutzen um zu ermitteln, ob eine Menge _s1_ eine _echte_ Teilmenge einer Menge _s2_ ist. Dies ist der Fall, wenn _s1_ eine Teilmenge von _s2_ ist und nicht die gleiche Menge ist." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "True\n" + ] + } + ], + "source": [ + "s1 = {1, 2, 3, 4}\n", + "s2 = {1, 2}\n", + "print(s2 < s1)\n", + "print(s1 > s2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## frozenset\n", + "Ein frozenset ist eine 'eingefrorene' Menge, das heißt sie ist unveränderlich. Die grundsätzlichen, oben besprochenen Methoden sind jedoch auch für ein `frozenset` Objekt vorhanden." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git "a/Level_03/L\303\266sungen/bubblesort.py" "b/Level_03/L\303\266sungen/bubblesort.py" new file mode 100755 index 0000000..ea8ee9e --- /dev/null +++ "b/Level_03/L\303\266sungen/bubblesort.py" @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +import random + +def get_random_list(n: int) -> list: + result = list(range(n)) + random.shuffle(result) + return result + +n = int(input("Länge der Liste: ")) +unsorted_list = get_random_list(n) + +# Bitte die Zeilen 1-12 unverändert lassen + +def bubblesort(unsorted_list: list) -> list: + changed = True + while changed: + changed = False + for i in range(len(unsorted_list)-1): + if unsorted_list[i] > unsorted_list[i+1]: + unsorted_list[i], unsorted_list[i+1] = unsorted_list[i+1], unsorted_list[i] + changed = True + +print(unsorted_list) +bubblesort(unsorted_list) +print(unsorted_list) \ No newline at end of file diff --git "a/Level_03/L\303\266sungen/fakultaet.py" "b/Level_03/L\303\266sungen/fakultaet.py" new file mode 100755 index 0000000..30d47c6 --- /dev/null +++ "b/Level_03/L\303\266sungen/fakultaet.py" @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +# Schreiben Sie ein Programm, das die Fakultät einer eingegebenen Zahl berechnet. +# Und überprüfen Sie mit Hilfe der vorgegebenen Werte 3! = 6, 4! = 24, 6! = 720 + +n = int(input("Bitte eine Zahl eingeben: ")) + +result = 1 +for i in range(1, n+1): + result = result * i # Alternativ: result *= i + +print(str(n) + "! = " + str(result)) + + +""" +# Alternativ: +counter = 1 +result = 1 +while counter <= n: + result = result * counter # Alternativ: result *= counter + counter = counter + 1 # Alternativ: counter += 1 + +print(str(n) + "! = " + str(result)) +""" diff --git "a/Level_03/L\303\266sungen/gau\303\237.py" "b/Level_03/L\303\266sungen/gau\303\237.py" new file mode 100755 index 0000000..d2f4737 --- /dev/null +++ "b/Level_03/L\303\266sungen/gau\303\237.py" @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +# Schreiben Sie ein Programm, dass die gaußsche Summe eine Zahl n iterativ und mit Hilfe der +# gaußschen Formel berechnet und vergleichen Sie die Ergebnisse (sollten Diskrepanzen auftreten +# ist Ihnen ein Fehler unterlaufen). + +n = int(input("Bitte geben Sie eine Zahl ein: ")) + +# Iterativ: +result_iter = 0 +for i in range(1, n+1): + result_iter += i + +# Gauß +result_gauß = int(n * (n + 1) / 2) + +print("Iterativ: " + str(result_iter)) +print("Gauß: " + str(result_gauß)) +print("Korrekt? " + str(result_iter == result_gauß)) + diff --git a/Level_03/README.md b/Level_03/README.md new file mode 100644 index 0000000..b06889b --- /dev/null +++ b/Level_03/README.md @@ -0,0 +1,51 @@ +# Level 3 Aufgaben + +Viele Algorithmen in der Mathematik lassen sich als Summen oder Produkte beschreiben. Diese wiederrum können mit Schleifen implementiert werden. Später werden wir allerdings noch einen anderen Weg kennenlernen solche Algorithmen zu implementieren (Rekursion). Im Folgenden soll die Benutzung von Schleifen an klassischen Beispielen geübt werden. + +## Aufgabe 1: Die Fakultät +Die Fakultät einer natürlichen Zahl `n` schreibt man als `n!` und ist das Produkt aller natürlichen Zahlen von 1 bis einschließlich n. +Wir schreiben: `n! = 1 * 2 * 3 * n-2 * n-1 * n`. +**Schreibe ein Programm, das die Fakultät einer eingegebenen Zahl berechnet. Und überprüfe mit Hilfe der vorgegebenen Werte.** + +``` +3! = 1 * 2 * 3 = 6 +4! = 1 * 2 * 3 * 4 = 24 +6! = 1 * 2 * 3 * 4 * 5 * 6 = 720 +``` + +**Hinweis:** Die Fakultät von n entspricht ungefähr 1,6^n, was bedeutet, das sie exponentiell wächst, weshalb aus Zeitgründen, das Programm nur mit niedrigen Zahlen getestet werden sollte. + +## Aufgabe 2: Die gaußsche Summe +Die gaußsche Summe von einer natürlichen Zahl n ist die Summe aller natürlicher Zahlen von 1 bis einschließlich n. +Wie zu sehen ist hat die gaußsche Summe große Ähnlichkeit mit der Fakultät, weshalb der Code nicht so stark verändert werden muss. Allerdings hat die gaußsche Summe den Vorteil, dass man sie nicht iterativ berechnen muss. Gauß soll für folgende Berechnungsmethode verantwortlich sein: +`n + n-1 + n-2 ... + 3 + 2 + 1 = n*(n+1)/2 ` + +**Schreibe ein Programm, dass die gaußsche Summe eine Zahl n iterativ und mit Hilfe der gaußschen Formel berechnet und vergleiche die Ergebnisse (sollten Diskrepanzen auftreten ist Dir ein Fehler unterlaufen).** + +## Aufgabe 3: Bubblesort +Bubblesort ist ein Sortieralgorithmus, das heißt eine Prozedur um Folgen zu sortieren. +Angenommen wir wollen eine Liste mit n Elementen, die jeweils ganze Zahlen sind, sortieren. +``` python +liste = [7, 4, 6, 2, 8, 1, 3, 5] +``` +Nun vergleichen wir jeweils zwei benachbarte Elemente: +``` +7 > 4 +4 < 6 +6 > 2 +2 < 8 +8 > 1 +1 < 3 +3 > 5 +``` +Wenn das vordere Element größer als das hintere Element ist, werden diese vertauscht. Bei jeder Vertauschung merken wir uns, das wir eine Vertauschung gemacht haben. Dies wird solange durchgeführt, bis es in einem Durchgang keine Vertauschung mehr gab. Dann ist die Liste sortiert. +``` +0 [7, 4, 6, 2, 8, 1, 3, 5] # Vertauscht = True +1 [4, 6, 2, 7, 1, 3, 5, 8] # Vertauscht = True +2 [4, 2, 6, 1, 3, 5, 7, 8] # Vertauscht = True +3 [2, 4, 1, 3, 5, 6, 7, 8] # Vertauscht = True +4 [2, 1, 3, 4, 5, 6, 7, 8] # Vertauscht = True +5 [1, 2, 3, 4, 5, 6, 7, 8] # Vertauscht = False +``` +Im Ordner Level_03/Vorgaben findet sich eine Datei "bubblesort.py". Diese erstellt eine Liste mit `n`Elementen und durchmischt diese, das bedeutet, dass kein Element doppelt auftauchen wird. + **Schreibe ein Programm in diese Datei, dass die Liste `unsortet_list` mit Hilfe von Bubblesort sortiert.** diff --git a/Level_03/bubblesort.py b/Level_03/Vorgaben/bubblesort.py similarity index 71% rename from Level_03/bubblesort.py rename to Level_03/Vorgaben/bubblesort.py index d13a9fd..43c4a41 100755 --- a/Level_03/bubblesort.py +++ b/Level_03/Vorgaben/bubblesort.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 import random -def get_random_list(n): +def get_random_list(n: int) -> list: result = list(range(n)) random.shuffle(result) return result - -n = int(input("Länge der Liste: ") + +n = int(input("Länge der Liste: ")) unsortet_list = get_random_list(n) # Bitte die Zeilen 1-12 unverändert lassen diff --git a/Level_03/dictionaries.py b/Level_03/dictionaries.py deleted file mode 100755 index febd7e7..0000000 --- a/Level_03/dictionaries.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 - -# Listentypen: - -# 3. Das Dictionary: - -# Ein Dictionary ist eine unsortierte Liste, in der -# immer ein /Wert einem /Schlüssel zugeordnet ist. - -# Ein Dictionary wird über geschweifte Klammern -# definiert: -dictionary = {"Eins": "one", "Zwei": "two"} -print(dictionary) - -# Auf einen value wird mit Hilfe des keys zu- -# gegriffen: -print(dictionary["Eins"]) - -# Ein neues Key-Value-Paar wird erstellt, -# indem auf ein nicht-existierenden value zu- -# gegriffen wird und dieser definiert wird: -dictionary["Wasser"] = "water" -print(dictionary) -# Als keys geeignet sind zum Beispiel: Integer, Strings, Tupel, Boolean - - -# Mit len() lässt sich die Länge ausgeben: -print(len(dictionary)) - - -# Die Schlüssel eines Dictionarys können als Liste zurückgegeben werden: -print(dictionary.keys()) - - -# ebenso wie die Values: -print(dictionary.items()) diff --git a/Level_03/fibonacci.py b/Level_03/fibonacci.py deleted file mode 100755 index a1f69a0..0000000 --- a/Level_03/fibonacci.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 -print ("""Fibonacci-Reihe: -Die Summe zweier Elemente ergibt das naechste.""") - -#a, b = 0, 1 -a = 0 -b = 1 -# while b < 50: -for sprechend in range(10): - print(a) - #a, b = b, a+b - n = a - a = b - b += n diff --git a/Level_03/for.py b/Level_03/for.py deleted file mode 100755 index dadc150..0000000 --- a/Level_03/for.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python3 - -# Schleifen: - -# 2. Die for-Schleife: - -# Die for-Schleife durchläuft ein iterierbares -# Objekt. Alle oben genannten Listen sind solche -# iterierbaren Objekte. -String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - -for char in String: - print(char) - -# Beim Durchlaufen eines Dictionary wird jedoch nur -# der key zurückgegeben: -Dictionary = {"one": "Eins", "two": "Zwei", "three": "drei"} -for key in Dictionary: - print(key) - print(Dictionary[key]) - - -# Ebenso kann ein Tupel oder eine Liste durchlaufen werden - -# Mit dem Befehl range() erschafft man ein iterierbares -# Objekt, das mit Zahlen gefüllt ist: -R = range(10) -print(list(R)) - -# Dabei kann man auch den Startwert und die Schrittweite -# angeben: -R = range(0, 101, 2) -print(list(R)) - -# Somit kann man eine Zählschleife implementieren: -R = range(10) -for i in R: - print(i) - -# oder: - -for i in range(10): - print(i) diff --git a/Level_03/listen.py b/Level_03/listen.py deleted file mode 100755 index 0e3ab38..0000000 --- a/Level_03/listen.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python3 - -# Listentypen: - -# 1. Die Liste: - -# Eine Liste ist eine beliebig lange Folge von beliebigen Objekten - -# Eine Liste wird mit Hilfe von eckigen Klammern definiert. -liste = [0, "foo"] -print(liste) - - -# Mit list() lässt sich bspw. ein String in einen Liste verwandeln: -print(list(String)) - - -# Auf ein Element in einer Liste wird über dessen Index -# zugegriffen. Der Index ist die Stelle, an der das Element -# steht. -# Wichtig: Die Zählung des Index beginnt mit 0, -# daher ist der Index des ersten Elements 0. -# Liste: [0, "foo"] -# Index: 0 1 - -element = liste[0] -print(element) - -# Die Funktion liefert für viele Objekte die Länge zurück. -# Bei einer Liste enspricht die Länge der Anzahl an Elementen. -l = len(liste) -print(l) - - -# Die append()-Methode fügt einer Liste ein beliebiges -# Element hinzu: -liste.append("bar") -print(liste) - - -# Statt ein Objekt am Ende einer Liste anzufügen, ist es auch möglich, -# es an einem Index einzusetzen. Dabei wird das Objekt vor dem Index -# eingesetzt. -liste.insert(0, "test") -print(liste) - - -# Die pop()-Methode löscht das Objekt an dem Index in der Liste. -# Ist kein Index angegeben lösht pop() das letzte Element -liste.pop() -print(liste) - - -# Ein Element kann aber nicht nur über den Index gelöscht werden, sondern -# auch über das Objekt, es wird allerdings nur das erste Auftreten des -# Objektes gelöscht. Dabei wird ein Fehler geworfen, falls das Objekt -# nicht in der Liste vorhanden ist. -liste2.remove(9) -print(liste2) - - -# Um festzustellen, wie oft ein Wert in einer Liste vorhanden ist kann -# die count()-Methode verwendet werden. -liste3 = list("aabbbcccc") -print(liste3.count("a")) -print(liste3.count("d")) - - -# Eine Liste kann mit sort() sortiert werden: -liste2 = [9,6,3,2,7] -liste2.sort() -print(liste2) - - -# Auf die einzelnen Zeichen eines Strings kann ebenfalls über den Index -# zugegriffen werden, wie bei einer Liste. -String = "ABCDEFGHIJKLMNOPQRSTUVW" -print(String) -print(String[4]) diff --git a/Level_03/tupel.py b/Level_03/tupel.py deleted file mode 100755 index 8202774..0000000 --- a/Level_03/tupel.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python3 - -# Listentypen: - -# 2. Das Tuple: - -# Ein Tuple ist eine unveränderliche und unsortierte -# Folge von Elementen. - -# Ein Tuple wird über runde Klammern definiert: -Tuple = ("foo", "bar") -print(Tuple) - -# Mit einem Index kann auf ein Element zugegriffen -# werden: -print(Tuple[0]) - -# Mit dem len()-Befehl lässt sich die Länge aus- -# geben: -print(len(Tuple)) diff --git a/Level_03/while.py b/Level_03/while.py deleted file mode 100755 index 44e7087..0000000 --- a/Level_03/while.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python3 - -# Schleifen: - -# 1. Die while-Schleife: - -# Im Kopf der while-Schleife steht eine Bedingung. -# Wenn die Begindung erfüllt ist, durchläuft die while-Schleife ihren Bauch. -# Danach prüft sie erneut die Bedingung. Und das immer so weiter. -counter = 0 - -while counter < 10: - counter += 1 - -# Endlosschleife: -""" -while True: - print("foo") -""" diff --git a/Level_04/Beispielcode/loremipsum.py b/Level_04/Beispielcode/loremipsum.py new file mode 100755 index 0000000..c556325 --- /dev/null +++ b/Level_04/Beispielcode/loremipsum.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +from pathlib import Path + +lorem_ipsum = Path("loremipsum.txt") +text = lorem_ipsum.read_text() # type: str + +orig = text +text = text.upper() + +if "U" in text: + text = text.replace("U", "V") + +print(orig) +print("****************") +print(text) + +lorem_ipsvm = Path("loremipsvm.txt") +lorem_ipsvm.write_text(text) diff --git a/Level_04/loremipsum.txt b/Level_04/Beispielcode/loremipsum.txt similarity index 100% rename from Level_04/loremipsum.txt rename to Level_04/Beispielcode/loremipsum.txt diff --git a/Level_04/loremipsvm.txt b/Level_04/Beispielcode/loremipsvm.txt similarity index 100% rename from Level_04/loremipsvm.txt rename to Level_04/Beispielcode/loremipsvm.txt diff --git a/Level_04/Level_4.ipynb b/Level_04/Level_4.ipynb new file mode 100644 index 0000000..cbecb83 --- /dev/null +++ b/Level_04/Level_4.ipynb @@ -0,0 +1,212 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Level 4\n", + "\n", + "In diesem Level geht es um Dateien.\n", + "\n", + "[`pathlib`](https://docs.python.org/3/library/pathlib.html) ist wahrscheinlich die beste Möglichkeit, mit Pfaden und Dateien zu hantieren." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from pathlib import Path\n", + "\n", + "# Referenz auf die Datei \"loremipsum.txt\"\n", + "ipsum = Path(\"Beispielcode\") / Path(\"loremipsum.txt\")\n", + "\n", + "# Existiert diese Datei? Ist es überhaupt eine Datei?\n", + "ipsum.exists() and ipsum.is_file()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wenn wir ein Referenz auf eine Datei haben, wollen wir mit der Datei auch etwas machen.\n", + "Das einfachste ist wahrscheinlich, die Datei komplett einzulesen:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.\\nVivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.\\nSuspendisse lectus leo, consectetur in tempor sit amet, placerat quis neque. Etiam luctus porttitor lorem, sed suscipit est rutrum non. Curabitur lobortis nisl a enim congue semper. Aenean commodo ultrices imperdiet. Vestibulum ut justo vel sapien venenatis tincidunt. Phasellus eget dolor sit amet ipsum dapibus condimentum vitae quis lectus. Aliquam ut massa in turpis dapibus convallis. Praesent elit lacus, vestibulum at malesuada et, ornare et est. Ut augue nunc, sodales ut euismod non, adipiscing vitae orci. Mauris ut placerat justo. Mauris in ultricies enim. Quisque nec est eleifend nulla ultrices egestas quis ut quam. Donec sollicitudin lectus a mauris pulvinar id aliquam urna cursus. Cras quis ligula sem, vel elementum mi. Phasellus non ullamcorper urna.\\nClass aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In euismod ultrices facilisis. Vestibulum porta sapien adipiscing augue congue id pretium lectus molestie. Proin quis dictum nisl. Morbi id quam sapien, sed vestibulum sem. Duis elementum rutrum mauris sed convallis. Proin vestibulum magna mi. Aenean tristique hendrerit magna, ac facilisis nulla hendrerit ut. Sed non tortor sodales quam auctor elementum. Donec hendrerit nunc eget elit pharetra pulvinar. Suspendisse id tempus tortor. Aenean luctus, elit commodo laoreet commodo, justo nisi consequat massa, sed vulputate quam urna quis eros. Donec vel. \\n'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ipsum.read_text()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "(bzw. `read_bytes` für Binärdateien)\n", + "\n", + "Das funktioniert für sehr kleine Dateien; bei großen Dateien geht das aber leider nicht mehr sinnvoll.\n", + "Mit `open` bekommen wir eine Referenz auf eine offene Datei, was uns viel mehr Spielraum gibt:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "Lorem\n", + "5\n", + "2\n", + "2\n", + "rem i\n" + ] + } + ], + "source": [ + "lorem_ipsum = (Path(\"Beispielcode\") / Path(\"loremipsum.txt\")).open(\"r\")\n", + "print(lorem_ipsum.tell())\n", + "print(lorem_ipsum.read(5))\n", + "print(lorem_ipsum.tell())\n", + "print(lorem_ipsum.seek(2))\n", + "print(lorem_ipsum.tell())\n", + "print(lorem_ipsum.read(5))\n", + "lorem_ipsum.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Mit `write` lässt sich entsprechend Text an die aktuelle Position des Zeigers schreiben." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Mit `write_text` bzw. `open(\"w\")` lässt sich eine Datei entsprechend zum (Über-)Schreiben öffnen:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "test = Path(\"test.txt\")\n", + "test.write_text(\"blub\")\n", + "test.unlink() # löscht die Datei wieder" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wenn die Datei nicht existiert (hat), wurde sie durch das `write_text` angelegt." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Mit `open(\"a\")` lässt sich auch Text an eine Datei anhängen: Der Zeiger wird direkt beim Öffnen auf das Dateiende gelegt. Wenn die Datei nicht existiert, wird sie auch hierbei angelegt." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Auch praktisch: mit `writeline` bzw. `writelines` lassen sich ganze Zeilen in die Datei schreiben:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "content = 10 * [\"spam\"]\n", + "filename = \"spam.txt\"\n", + "file_object = open(filename, \"w\")\n", + "file_object.writelines(content)\n", + "file_object.close()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Ordner gibt es natürlich auch. Wir können sie z.B. anlegen oder löschen:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "test_dir = Path(\"testdir\")\n", + "test_dir.mkdir()\n", + "test_dir.rmdir()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Level_04/monty.txt "b/Level_04/L\303\266sungen/monty.txt" similarity index 99% rename from Level_04/monty.txt rename to "Level_04/L\303\266sungen/monty.txt" index 5915861..c2622e7 100644 --- a/Level_04/monty.txt +++ "b/Level_04/L\303\266sungen/monty.txt" @@ -1,3 +1,5 @@ +# Auszug aus https://de.wikipedia.org/wiki/Monty_Python unter der CC-by-sa Lizenz. # + Monty Python Monty Python war eine britische Komikergruppe. Sie wurde 1969 gegründet und hatte ihre Blütezeit in den 1970er Jahren, in denen die Fernsehserie Monty Python’s Flying Circus und mehrere Kinofilme, unter anderem Das Leben des Brian, entstanden. diff --git "a/Level_04/L\303\266sungen/monty_a.py" "b/Level_04/L\303\266sungen/monty_a.py" new file mode 100755 index 0000000..d527110 --- /dev/null +++ "b/Level_04/L\303\266sungen/monty_a.py" @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 + +# Dies ist eine Beispiellösung für Aufgabe 2a aus Level 4 +# Schreibe ein Programm, dass: +# die Datei `monty.txt` aus dem Code-Repository einliest, +# * eine Worthäufigkeitstabelle erstellt, +# * eine Buchstabenhäufigkeitstabelle erstellt, +# * die Worthäufigkeiten lesbar formatiert in "words.txt" abspeichert, +# * und die Buchstabenhäufigkeiten lesbar formatiert in "chars.txt" speichert. + +# Wir benötigen die Bibliothek pathlib für einige Funktionen: +from pathlib import Path + +path_text = Path("monty.txt") +path_words = Path("words.txt") +path_chars = Path("chars.txt") + +# 1. Einlesen des Textes: + +if path_text.exists(): + file_obj = path_text.open("r") # Öffnen der Datei + text = file_obj.read() # Einlesen des Textes + file_obj.close() # Schließen des Dateiobjekts +else: + print(f"Die Datei {path_text} existiert nicht.") + exit() + +# Alternativ: +# with path_text.open("r") as file_obj: +# text = file_obj.read() + +# 2. Worthäufigkeitstabelle +text = text.replace("\n"," ") # entfernen der Return-Steuerzeichen +text = text.lower() # der ganze Text in Kleinbuchstaben +words = text.split(" ") # Aufteilen am Leerzeichen + +word_count = {} +for element in words: + if element.isalpha(): # handelt es sich um ein Wort + if element in word_count: + word_count[element] += 1 + else: + word_count[element] = 1 + + +# 3. Buchstabenhäufigkeitstabelle: +char_count = {} +for char in text: + if char.isalpha(): # handelt es sich um einen Buchstaben + if char in char_count: + char_count[char] += 1 + else: + char_count[char] = 1 + + +# 4. Abspeichern der Tabellen: +# Worthäufigkeiten: +file_obj = path_words.open("w") +for word, count in word_count.items(): + line = f"{word};{count}\n" + file_obj.writelines([line]) +file_obj.close() + +# Buchstabenhäufigkeiten: +file_obj = path_chars.open("w") +for char, count in char_count.items(): + line = f"{char};{count}\n" + file_obj.writelines([line]) +file_obj.close() diff --git "a/Level_04/L\303\266sungen/monty_b.py" "b/Level_04/L\303\266sungen/monty_b.py" new file mode 100755 index 0000000..3478c27 --- /dev/null +++ "b/Level_04/L\303\266sungen/monty_b.py" @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +# Dies ist eine Beispiellösung für Aufgabe 2b aus Level 4 +# * einen Integer n einliest, +# * die Häufigkeitstabelle der Buchstaben aus der, zuvor erstellten, Datei +# "chars.txt" einliest und +# * die n häufigsten und die n seltenen Buchstaben ausgibt. + +from pathlib import Path + +path = Path("chars.txt") + +# Eingabe Integer n: +n = input("Bitte eine Zahl eingeben: ") +if n.isdigit(): + n = int(n) +else: + print("Es wurde keine Zahl eingegeben.") + exit() + +# Einlesen der Datei: +if not path.exists(): + print(f"Die Datei {path} wurde nicht gefunden.") + exit() + +table = {} +file_obj = path.open("r") +for line in file_obj: + key = line.split(";")[0] + value = int(line.split(";")[1]) + table[key] = value +file_obj.close() + +# Sortieren +tmp = list(table.items()) +table = [] +for i in range(len(tmp)): + max_key = 0 + max_value = 0 + for index in range(len(tmp)): + entry = tmp[index] + if entry[1] > max_value: + max_key = index + max_value = entry[1] + max_entry = tmp[max_key] + table.append(max_entry) + tmp.remove(max_entry) + + +# Ausgeben der n häufigsten und n seltenen Buchstaben: +common = [] +rare = [] + +for entry in table[0:n]: + common.append(entry[0]) + +for entry in table[-(n+1):-1]: + rare.append(entry[0]) + +print(f"Die {n} häufigsten Buchstaben sind: ") +print(common) + +print(f"Die {n} seltenen Buchstaben sind: ") +print(rare) diff --git "a/Level_04/L\303\266sungen/monty_c.py" "b/Level_04/L\303\266sungen/monty_c.py" new file mode 100755 index 0000000..8287795 --- /dev/null +++ "b/Level_04/L\303\266sungen/monty_c.py" @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +# Dies ist eine Beispiellösung für Aufgabe 2c aus Level 4 +# Schreiben Sie ein Programm, dass: +# * die Datei `monty.txt` öffnet und den Inhalt einliest, +# * im eingelesenen Inhalt jedes Auftauchen des Wortes `Python` durch `PYTHON` +# ersetzt, +# * und den entstandenen Text in einer Datei `MONTY.txt` +# (auf Windows unter `monty_upper.txt`) speichert + +# Wir benötigen die Bibliothek pathlib für einige Funktionen: +from pathlib import Path + +path_text = Path("monty.txt") +path_new = Path("MONTY.txt") + +# 1. Einlesen des Textes: +if path_text.exists(): + file_obj = path_text.open("r") + text = file_obj.read() + file_obj.close() +else: + print(f"Die Datei {path_text} existiert nicht.") + exit() + +# 2. "Python" ersetzen: +new_text = text.replace("Python", "PYTHON") + +# 3. Neuen Text in neue Datei schreiben: +file_obj = path_new.open("w") +file_obj.write(new_text) +file_obj.close() diff --git "a/Level_04/L\303\266sungen/quine.py" "b/Level_04/L\303\266sungen/quine.py" new file mode 100755 index 0000000..90ce49e --- /dev/null +++ "b/Level_04/L\303\266sungen/quine.py" @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from pathlib import Path + +we = Path(__file__) +print(we.read_text()) diff --git a/Level_04/README.md b/Level_04/README.md new file mode 100644 index 0000000..f3dd538 --- /dev/null +++ b/Level_04/README.md @@ -0,0 +1,35 @@ +# Level 4 Aufgaben +## Aufgabe 1 (Quine) +Schreibe ein Programm, dass seinen Quellcode ausgibt. + +## Aufgabe 2 (Monty Python) +### a) +**Schreibe ein Programm, dass:** + +* die Datei `monty.txt` aus dem Code-Repository einliest, +* eine Worthäufigkeitstabelle erstellt, +* eine Buchstabenhäufigkeitstabelle erstellt, +* die Worthäufigkeiten lesbar formatiert in "words.txt" abspeichert, +* und die Buchstabenhäufigkeiten lesbar formatiert in "chars.txt" speichert. + +### b) +**Schreibe ein Programm, dass:** + +* einen Integer `n` einliest, +* die Häufigkeitstabelle der Buchstaben aus der, zuvor erstellten, Datei `chars.txt`einliest, +* die `n` häufigsten und die `n` seltenen Buchstaben ausgibt. + +### c) +**Schreibe ein Programm, dass:** + +* die Datei `monty.txt` öffnet und den Inhalt einliest, +* im eingelesenen Inhalt jedes Auftauchen des Wortes `Python` durch `PYTHON` ersetzt, +* und den entstandenen Text in einer Datei `MONTY.txt` (auf Windows unter `monty_upper.txt`) speichert + +## Tipps: + +1. Überlege dir für Aufgabe 2 eine sinnvolle Formatierung, um die +Tabellen in den Dateien zu speichern. +2. Überlege dir eine Methode, um die Wörter zählen zu können +3. Bedenke, dass für die Häufigkeit von Buchstaben irrelevant ist, +ob diese groß oder klein geschrieben wurden. diff --git a/Level_04/dateien.py b/Level_04/dateien.py deleted file mode 100755 index 79b58d3..0000000 --- a/Level_04/dateien.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 - -# Level 4: Dateien - -import os - -# Existiert eine Datei? - -os.path.exists("lorem_ipsum.txt") -# OUT: False -os.path.exists("loremipsum.txt") -# OUT: True - -# einen Ordner erstellen - -os.mkdir("test") - -# eine Datei auslesen - -lorem_ipsum = open("loremipsum.txt", "r") -print(lorem_ipsum.read()) -lorem_ipsum.close() - -# eine Datei schreiben - -test = open("test/test.txt", "w") -test.write("total toller Text") -test.close() -# OUT: 17 - -# eine Datei löschen - -os.remove("test/test.txt") - -# einen Ordner löschen - -os.rmdir("test") diff --git a/Level_04/loremipsum.py b/Level_04/loremipsum.py deleted file mode 100755 index 6a70003..0000000 --- a/Level_04/loremipsum.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python3 - -lorem_ipsum = open("loremipsum.txt", "r") -text = lorem_ipsum.read() -lorem_ipsum.close() - -orig = text -text = text.upper() - -if "U" in text: - text = text.replace("U", "V") - -print(text) -print(orig) - -lorem_ipsvm = open("loremipsvm.txt", "w") -lorem_ipsvm.write(text) -lorem_ipsvm.close() diff --git a/Level_04/quine.py b/Level_04/quine.py deleted file mode 100755 index 7a47e99..0000000 --- a/Level_04/quine.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env python3 - -we = open(__file__, "r") -print(we.read()) -we.close() diff --git a/Level_05/Beispielcode/calculator05.py b/Level_05/Beispielcode/calculator05.py new file mode 100644 index 0000000..c9fab20 --- /dev/null +++ b/Level_05/Beispielcode/calculator05.py @@ -0,0 +1,198 @@ +""" +Das folgende Programm ist ein einfacher Taschenrechner. + +Nach dem Eingeben zweier Zahlen kann eine Operation ausgewählt werden. +Anschließend wird nach neuen Zahlen gefragt. +""" + +# Für die Berechnung der Quadratwurzel wird die math Bibliothek benötigt, +# des Weiteren wird zum vorzeitigen Beenden die sys Bibliothek benötigt. +import math +import sys + + +def menu(): + """Zeigt ein Menü an.""" + # Zuerst eine Willkommensnachricht + print() + print("Dies ist ein einfacher Taschenrechner.") + + # Diese Endlosschleife wird durch Aufruf der quit Funktion beendet + while True: + print() + counter = 0 + for fun in operations: + print(f"{counter} {fun.__name__}") + counter += 1 + print("Bitte eine Zahl für eine der Operationen angeben") + choice = input(":") + choice = int(choice) + print() + if choice < 0 or choice >= len(operations): + print("Die Eingabe war zu groß.") + continue + else: + operations[choice]() + + +def add(): + """ + Addiert zwei eingegebene Zahlen. + + Die Zahlen können sowohl ganze Zahlen (integer) oder Fließkommazahlen + (float) sein. + """ + sum1 = input("Bitte den ersten Summanden eingaben: ") + sum2 = input("Bitte den zweiten Summanden eingeben: ") + result = float(sum1) + float(sum2) + print(f"{sum1} + {sum2} = {result}") + + +def sum(): + """ + Summiert eine Menge an Zahlen auf. + + Die Summanden können sowohl ganze Zahlen (integer) oder Fließkommazahlen + (float) sein. + """ + values = input("Bitte die Summanden mit Leerzeichen getrennt eingeben:\n") + values = values.split(" ") + result = 0.0 + for i in values: + result += float(i) + print(f"sum({values}) = {result}") + + +def product(): + """ + Multipliziert eine Menge an Zahlen auf. + + Die Faktoren können sowohl ganze Zahlen (integer) oder Fließkommazahlen + (float) sein. + """ + values = input("Bitte die Faktoren mit Leerzeichen getrennt eingeben:\n") + values = values.split(" ") + result = 1.0 + for i in values: + result *= float(i) + print(f"product({values}) = {result}") + + +def difference(): + """ + Subtrahiert eine Zahl von einer anderen. + + Minuend und Subtrahend können sowohl ganze Zahlen (integer) oder + Fließkommazahlen (float) sein. + """ + minu = input("Bitte den Minuenden eingeben: ") + subt = input("Bitte den Subtrahenden eingeben: ") + result = float(minu) - float(subt) + print(f"{minu} - {subt} = {result}") + + +def quotient(): + """ + Teilt einen Divisor durch einen Dividenden. + + Dividend und Divisor können sowohl ganze Zahlen (integer), als auch + Fließkommazahlen (float) sein. 0 oder 0.0 sind als Divisor nicht möglich. + """ + divid = input("Bitte den Dividenden eingeben: ") + divis = input("Bitte den Divisor eingeben: ") + if float(divis) == 0.0: + print("Ungültige Divisor.") + return + result = float(divid) / float(divis) + print(f"{divid} / {divis} = {result}") + + +def modulo(): + """ + Gibt das Ergebnis einer Modulo Division zurück. + + Dividend und Divisor müssen ganze Zahlen sein. 0 ist als Divisor nicht + möglich. + """ + divid = input("Bitte den Dividenden eingeben: ") + divis = input("Bitte den Divisor eingeben: ") + if float(divis) == 0.0: + print("Ungültige Divisor.") + return + result = int(divid) % int(divis) + print(f"{divid} % {divis} = {result}") + + +def sqrt(): + """ + Berechnet die Quadratwurzel einer eingegebenen Zahl. + + Die Zahl kann sowohl eine ganze Zahl (integer) als auch eine Fließkommazahl + (float) sein. + """ + radiant = input("Bitte eine Zahl eingeben: ") + result = math.sqrt(float(radiant)) + print(f"sqrt({radiant}) = {result}") + + +def power(): + """ + Berechnet eine Potenz. + + Basis und Exponent können sowohl ganze Zahlen (integer), als auch + Fließkommazahlen (float) sein. + """ + base = input("Bitte die Basis eingeben: ") + exp = input("Bitte den Exponenten eingeben: ") + result = pow(float(base), float(exp)) + print(f"{base} ^ {exp} = {result}") + + +def fak(): + """ + Berechnet die Fakultät einer Zahl. + + Die Zahl sollte eine positive ganze Zahl (natürliche Zahl) sein. + """ + x = input("Bitte eine Zahl eingeben: ") + result = 1 + for i in range(2, int(x) + 1): + result *= i + print(f"{x}! = {result}") + + +def help(): + """ + Ruft das Hilfe Menü auf. + + Das Hilfe Menü zeigt die Docstrings der einzelnen Funktionen an. + """ + for fun in operations: + print(fun.__name__) + print(fun.__doc__) + + +def quit(): + """Beendet das Programm.""" + sys.exit(0) + + +# Die Funktionen für die Operationen werden in einem Tuple gespeichert +operations = ( + add, + sum, + product, + difference, + quotient, + modulo, + sqrt, + power, + fak, + help, + quit +) + +# Durch diese Bedingung wird das Menü nur aufgerufen, wenn das Programm als +# Hauptprogramm läuft. +if __name__ == "__main__": + menu() diff --git a/Level_05/Beispielcode/fibonacci.py b/Level_05/Beispielcode/fibonacci.py new file mode 100755 index 0000000..8891d39 --- /dev/null +++ b/Level_05/Beispielcode/fibonacci.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +""" +Dieses Programm berechnet die Fibonacci-Reihe (rekursiv). +Dabei gilt: Die Summe zweier Elemente ergibt das Nächste. + +(In Level 3 findet sich eine iterative Implementation.) +""" + +# Die Fibonacci-Folge ist rekursiv definiert +# - trotzdem ist die rekursive Berechnung ziemlich ineffizient im Vergleich zur Iterativen; +# siehe dazu https://github.com/pythonfoo/pythonfooLite/wiki/Rekursion_Vs._Iteration. +# Eine wesentlich performantere Version findet sich in Level 7. + + +def fib(n: int) -> int: + # Die ersten beiden Elemente sind fix: + if n <= 1: + return n + # Ansonsten: f(n) = f(n-1) + f(n-2) + return fib(n - 1) + fib(n - 2) + + +n = int(input("Welches Element soll berechnet werden? ")) +print(" =>", fib(n)) diff --git a/Level_05/Beispielcode/ggT.py b/Level_05/Beispielcode/ggT.py new file mode 100755 index 0000000..f14f084 --- /dev/null +++ b/Level_05/Beispielcode/ggT.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +""" +Dieses Programm implementiert den euklidischen Algorithmus zur Bestimmung des größten gemeinsamen Teilers zweier Zahlen rekursiv. + +(In Level 3 findet sich eine iterative Implementation.) +""" + +# Berechnung +def ggT(a: int, b: int) -> int: + # Beide Zahlen sollten positiv sein. + # Wir nehmen einfach den Betrag. + a = abs(a) + b = abs(b) + + # a soll größer sein als b. + # Falls das nicht bereits der Fall ist, + # tauschen wir die beiden einfach. + if b > a: + return ggT(b, a) + + # Wenn b Null ist, sind wir fertig und a ist der ggT. + # Ansonsten müssen wir (nochmal) rechnen. + if b == 0: + return a + + # Teile a mit Rest durch b; + # setze a auf b + # und b auf den Rest. + return ggT(b, a%b) + +# Eingabe +a = int(input("erste Zahl eingeben: ")) +b = int(input("zweite Zahl eingeben: ")) + +# Ausgabe +print("Der größte gemeinsame Teiler dieser Zahlen ist:", ggT(a, b)) diff --git a/Level_05/Interessantes.md b/Level_05/Interessantes.md new file mode 100644 index 0000000..5d5ac29 --- /dev/null +++ b/Level_05/Interessantes.md @@ -0,0 +1,18 @@ +# Level 5.5 +Oder auch, Dinge, die auch interessant und/oder wichtig sind, in bisherigen Leveln aber keinen Platz gefunden haben. +## IDE, Texteditor oder doch Interpreter? +Es ist uns egal, wie ihr euren Code schreibt. Es ist möglich einen Texteditor zu benutzen in der Konsole zu benutzen, wie zum Beispiel `vim` oder `nano`, einen Texteditor mit graphischer Oberfläche, wie zum Beispiel `gedit`, einen Texteditor mit Syntax Hervorhebung (engl. syntax highlighting), wie zum Beispiel `notepad++` oder `Sublime Text`, eine IDE, wie zum Beispiel `PyCharm` oder `geany` oder den Code in den Interpreter zu schreiben. Uns ist nur wichtig, dass ihr mit dem entsprechenden Programm Code schreiben könnt. Natürlich können wir euch sagen, welches Programm wir benutzen, was uns daran gefällt und was nicht. Wir können euch sagen, was wir bei verschiedenen Programmen besonders praktisch finden, sei es Autovervollständigung, PEP 8 Check, Syntax Hervorhebung, GitHub Integration oder ähnliches. Wir können euch wahrscheinlich bei Problemen mit euren Texteditor/IDE der Wahl natürlich am ehesten helfen, wenn wir das entsprechende Programm kennen. + +### Beispielprogramme: +#### Texteditor in der Konsole +* vi +* vim +* nano +#### Texteditor mit graphischer Oberfläche +* gedit +* sublime text (2/3) +* notepad++ +* Atom +#### IDE +* PyCharm +* geany \ No newline at end of file diff --git a/Level_05/Level_5.ipynb b/Level_05/Level_5.ipynb new file mode 100644 index 0000000..5689789 --- /dev/null +++ b/Level_05/Level_5.ipynb @@ -0,0 +1,488 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8a8cb1fc", + "metadata": {}, + "source": [ + "Mit Hilfe von Funktionen ist es möglich Codeabschnitte bzw. kleinere Programmteile zu speichern und wiederzuverwenden. So wird die Komplexität stark reduziert.\n", + "Durch Funktionen muss du dich beim Schreiben eines Hello-World-Programms nicht erst mit der Kommunikation mit dem System Output kümmern oder um die Dekodierung deiner Eingabe. Du kannst einfach die print() Funktion benutzen, die alles wichtige für dich erledigt, sodass du nur noch Text eingeben musst.\n", + "Python liefert nun eine ganze Menge grundlegender Funktionen mit, was dir die Arbeit unglaublich erleichtert. Viele dieser Funktionen haben wir bereits in den vorherigen Levels behandelt und sie auch als Funktionen bezeichnet, ohne näher darauf einzugehen.\n", + "Beispiele für diese grundlegenden Funktionen sind:\n", + "\n", + "* `print()`\n", + "* `len()`\n", + "* `input()`\n", + "\n", + "Aber auch viele Funktionen, die zu einem Objekt gehören (solche Funktionen nennen wir \"Methoden\", dazu mehr im nächsten Level):\n", + "\n", + "* `list.append()`\n", + "* `list.count()`\n", + "* `list.pop()`\n", + "\n", + "Um aber nicht auf die Menge der mitgelieferten oder aus Drittquellen bezogenen (auch dazu mehr im nächsten Level) Funktionen beschränkt zu sein, bietet Python wie viele andere Programmiersprachen, die Möglichkeit eigene Funktionen zu definieren. Dadurch kann ich kleine Teile des Programms vorhalten und sie genau dann benutzen, wenn ich sie brauche.\n", + "Der Name Funktion mag andeuten, dass es sich dabei um etwas ähnliches wie eine mathematische Funktion handelt, das ist jedoch nur zum Teil richtig. Während eine mathematische Funktion einen festen Definitionsbereich besitzt, der aus mathematischen Objekten beruht, nimmt eine Funktion in Python beliebige Objekte entgegen und verarbeitet diese. Mit einer Python-Funktion kann ich beliebige mathematisch Funktionen definieren, andersherum ist das deutlich schwieriger. Die Analogie des Ablaufs oder der Prozedur ist daher eventuell angebrachter. Wir werden im folgenden trotzdem den Begriff Funktion verwenden." + ] + }, + { + "cell_type": "markdown", + "id": "7aeaaa2c", + "metadata": {}, + "source": [ + "## Die Funktionsdefinition\n", + "Im Folgenden wollen wir eine Funktion definieren, die genau das macht was ein Hello-World-Programm auch macht: \"Hello World\" ausgeben" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "1bd2230e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hello world\n" + ] + } + ], + "source": [ + "def hello_world():\n", + " print(\"hello world\")\n", + "hello_world()" + ] + }, + { + "cell_type": "markdown", + "id": "5e5615bd", + "metadata": {}, + "source": [ + "`def`ist ein Schlüsselwort, das zu Beginn einer Funktionsdefinition steht. Danach folgt der Funktionsname `hello_world`, für den die gleichen syntaktischen Anforderungen gelten, wie für Variablennamen, da `hello_world`in diesem Fall eine Variable ist. Demnach kann eine Funktion auch überschrieben werden, wie jede andere Variable auch. Darauf folgt eine leere runde Klammer in die Funktionsparameter eingetragen werden könnten. Darauf folgt ein Doppelpunkt und die Funktionssignatur ist abgeschlossen. Der darauf folgende Block ist eingerückt und muss zwangsweise Code enthalten. Nach der Funktionsdefinition wird die Funktion über ihren Namen, bzw. den Namen ihrer Variable, in dem Fall `hello_world`aufgerufen. Die runden Klammern am Ende der des Funktionsnamens stehen dabei für einen Aufruf und können eventuelle Parameter enthalten.\n", + "Diese Funktion macht aktuell noch keinen Sinn, da sie nur einen festgelegten String (\"hello world\") ausgeben kann.\n", + "\n", + "Nun wollen wir unsere Funktion ein wenig aufpeppen, indem wir ihr einen Parameter übergeben, sodass sie beliebige Strings ausgeben kann." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "eb2fce52", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Testeingabe\n" + ] + } + ], + "source": [ + "def new_print(text):\n", + " print(text)\n", + "inp_text = input(\"Eingabe: \")\n", + "new_print(inp_text)" + ] + }, + { + "cell_type": "markdown", + "id": "25b92a60", + "metadata": {}, + "source": [ + "Der Parameter wurde, wie bereits erwähnt in die runden Klammern eingetragen. `text`ist nun eine Variable und steht in der Funktion zur Verfügung. Im Funktionsaufruf haben wir unserer Funktion `new_print`die Variable `inp_text` übergeben, die zu dem Zeitpunkt den String `\"Testeingabe\"` enthielt. Dieser String wurde nun ausgegeben.\n", + "\n", + "## Rückgabewerte\n", + "\n", + "In den meisten Anwendungsfällen wollen wir das Ergebnis einer Funktion allerdings nicht ausgeben, sondern zum Beispiel in einer Variablen speichern können, um es später verwenden zu können. Dafür benötigt unsere Funktion einen Rückgabewert. Mit Hilfe eines Rückgabewertes kann eine Funktion ein Objekt beliebigen Typs zurückgeben, damit es weiter benutzt werden kann. Die folgende Funktion hat nun einen anderen Anwendungsfall verfügt jedoch über einen Übergabeparameter und einen Rückgabewert." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "72e337d0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "25" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def square(x):\n", + " return x**2\n", + "square(5)" + ] + }, + { + "cell_type": "markdown", + "id": "302d6450", + "metadata": {}, + "source": [ + "Die Funktion `square` nimmt einen Parameter entgegen (sollte dieser weder `int` noch `float` sein, wird ein Fehler geworfen). Dieser wird nun erst quadriert und danach über das Schlüsselwort `return` zurückgegeben. Wichtig zu beachten ist, dass alles, was nach einem `return` in der selben Einrückungsebene steht, nicht mehr ausgeführt wird. Folglich kann es in einem Einrückungsblock nur ein `return` geben (natürlich kann man mehr hinschreiben, diese werden jedoch nicht ausgeführt werden und sind daher sinnlos). Ein `return`beendet also die Definition einer Funktion. Der Rückgabewert einer Funktion kann nun entweder direkt verwendet werden (wie oben im Beispiel) oder in einer Variable abgespeichert werden um später benutzt zu werden. Ebenfalls wichtig zu beachten ist, dass mit `return`immer nur ein Objekt zurückgegeben werden kann. Falls man mehrere Objekte zurückgeben möchte, sollte man sie in eine Liste, Tupel oder Dictionary packen.\n", + "\n", + "## args und kwargs\n", + "Bisher können wir einer Funktion einen Parameter geben und einen Rückgabewert zurückgeben lassen. Allerdings benötigen viele Anwendungsfälle Funktionen, die mehrere Objekte entgegen nehmen können, d.h. die mehrere Parameter haben können. Nun wäre der naive Ansatz, der schon bei Rückgabewerten benutzt wurde, statt mehreren Parametern eine Liste von Parametern zu übergeben. Praktischerweise ist in Python dieser Ansatz implementiert. Zuerst wollen wir aber zwei verschiedene Fälle unterscheiden:\n", + "\n", + "1. Die Menge an Parametern ist fest.\n", + "2. Die Menge an Parametern ist variabel\n", + "\n", + "Diese Unterscheidung ist sehr wichtig, da die Verwendung von mehreren Parametern sich danach unterscheidet." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "01d28a10", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "-2\n" + ] + } + ], + "source": [ + "def diff(a, b):\n", + " return a - b\n", + "print(diff(5, 3))\n", + "print(diff(3, 5))" + ] + }, + { + "cell_type": "markdown", + "id": "9517e691", + "metadata": {}, + "source": [ + "Wenn ich eine feste Anzahl an Parametern benutzen möchte, kann ich diese in der Signatur auflisten. Wichtig ist dabei, dass beim Aufruf die Reihenfolge entscheidend ist. Die obige Funktion subtrahiert das Objekt der Variable `b` von dem Objekt der Variable `a`, daher sind `a` und `b` idealerweise ganze Zahlen oder Fließkommazahlen. Beim Aufruf wird das n-te Element im Aufruf dem n-ten Element der Signatur zugeordnet (hier kann man die Benutzung einer Liste oder eines Tupels erkennen).\n", + "\n", + "Nun möchte ich aber einer Funktion eine beliebige Anzahl an Parametern übergeben, weil ich zum Beispiel nicht weiß, wie viele Parameter zur Laufzeit benötigt werden." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "7e8cee93", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'01test'" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def string_add(*elemente):\n", + " result = \"\"\n", + " for e in elemente:\n", + " result += str(e)\n", + " return result\n", + "string_add(0, 1, \"test\")" + ] + }, + { + "cell_type": "markdown", + "id": "a518055c", + "metadata": {}, + "source": [ + "Das `*elemente` steht dabei für ein Tupel und kann innerhalb der Funktion als Tupel mit dem Variablennamen `elemente` behandelt werden. Wichtig zu wissen ist, dass `*args` auch leer sein kann, wenn keine Argumente übergeben wurden. Manchmal ist es jedoch vorteilhaft eine Funktion zu definieren, die mindestens n Parameter entgegennimmt und danach beliebig viele weitere, dabei ist es wichtig, das die `*args` Argumente in der Signatur nach den positionalen Parametern kommen." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "5b5c4ef5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "12" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def add_int(summand_a, summand_b, *more_summands):\n", + " result = summand_a + summand_b\n", + " for summand in more_summands:\n", + " result += summand\n", + " return result\n", + "add_int(1, 5, 6)" + ] + }, + { + "cell_type": "markdown", + "id": "fdaf7e63", + "metadata": {}, + "source": [ + "Noch viel praktischer ist es, wenn man Standartwerte angeben kann, die benutzt werden, wenn keine Parameter angegeben werden. Für diesen Anwendungsfall gibt keyword arguments, kurz kwargs." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "7cfc0f32", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "123456\n", + "123456\n" + ] + } + ], + "source": [ + "def pwd_input(prompt=\"Passwort: \"):\n", + " return input(prompt)\n", + "print( pwd_input(\"pwd: \"))\n", + "print( pwd_input() )" + ] + }, + { + "cell_type": "markdown", + "id": "2afe8680", + "metadata": {}, + "source": [ + "Es ist auch möglich, eine beliebige Anzahl von keyword arguments zu benutzen. Dabei werden die Parameter als Dictionary interpretiert." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "db791f61", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dict_keys(['test1', 'test2'])\n", + "dict_values(['foo', 'test'])\n" + ] + } + ], + "source": [ + "def fun(**kwargs):\n", + " print(kwargs.keys())\n", + " print(kwargs.values())\n", + "fun(test1 = \"foo\", test2 = \"test\")" + ] + }, + { + "cell_type": "markdown", + "id": "515dec33", + "metadata": {}, + "source": [ + "## Rekursion\n", + "Es ist nicht nur möglich innerhalb einer Funktion Kontrollstrukturen wie eine if-Bedingung oder eine for-Schleife benutzen, sondern auch Funktionen aufrufen und insbesondere die eigene Funktion aufrufen. Wir nennen es Rekursion, wenn eine Funktion sich selber aufruft. Rekursion kann, wie Schleifen, benutzt werden, um verschiedene mathematische Algorithmen zu implementieren. Allerdings unterscheidet sich die Nutzung von Rekursion gegenüber der Nutzung von Schleifen, bei der Implementierung von Algorithmen, insofern, dass es ein Rekursionslimit gibt, wohingegen eine while-Schleife endlos laufen kann." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "e0400629", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3000\n" + ] + }, + { + "data": { + "text/plain": [ + "1200" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import sys\n", + "print( sys.getrecursionlimit() )\n", + "sys.setrecursionlimit(1200)\n", + "sys.getrecursionlimit()" + ] + }, + { + "cell_type": "markdown", + "id": "ed5247cf", + "metadata": {}, + "source": [ + "Wie oben zu sehen ist, kann das Rekursionslimit zwar geändert werden, die Tatsache, dass es ein Limit gibt, beschränkt trotzdem die Art der Algorithmen, die mit Rekursion implementiert werden können.\n", + "\n", + "### WARNUNG: LIMIT\n", + "Um nicht in das Rekursionslimit zu laufen, sollte Rekursion in der Praxis nur angewendet werden, wenn die Anzahl der rekursiven Aufrufe bekannt oder bekannt gering ist.\n", + "In realen Einsatzbereichen kommt es immer wieder zu schwer lösbaren Fehlern, wenn diesem Problem nicht rechtzeitig Aufmerksamkeit geschenkt wird.\n", + "\n", + "### WARNUNG: Kompliziert\n", + "Das Debuggen von Rekursiven aufrufen kann extrem Kompliziert werden. Das sollte unbedingt beachtet werden, wenn ein Programm einem realen Einsatzzweck zugeführt werden soll und ob eine Lösung mit einer Schleife nicht besser geeignet wäre." + ] + }, + { + "cell_type": "markdown", + "id": "1e2cdfb1", + "metadata": {}, + "source": [ + "# Zeit\n", + "\n", + "Dieser Abschnitt zeigt ein paar Funktionen von `time`.\n", + "\n", + "Damit kann man z.B. die aktuelle Uhrzeit abfragen:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "bf3ede3e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Timestamp: 1763056857.404581\n", + "strukturierte Daten: time.struct_time(tm_year=2025, tm_mon=11, tm_mday=13, tm_hour=19, tm_min=0, tm_sec=57, tm_wday=3, tm_yday=317, tm_isdst=0)\n" + ] + } + ], + "source": [ + "import time\n", + "print(\"Timestamp:\", time.time())\n", + "print(\"strukturierte Daten:\", time.localtime())" + ] + }, + { + "cell_type": "markdown", + "id": "3ba3f394", + "metadata": {}, + "source": [ + "# mehr String-Funktionen\n", + "\n", + "## Escaping\n", + "\n", + "Es gibt Zeichen, die man nicht eingeben kann. Stattdessen lassen sich diese über\n", + "Backslash-Escapes benutzen:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc0d83bc", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Tab:\\t#\")\n", + "print(\"Wal: \\N{WHALE}\")\n", + "print(\"\\aabc\")\n", + "print(\"\\\\0/\") # der Backslash selbst\n", + "# Rawstrings können kein escaping:\n", + "print(r\"\\n\")\n", + "print(r\"\\0/\")" + ] + }, + { + "cell_type": "markdown", + "id": "bb476ec4", + "metadata": {}, + "source": [ + "## Formatting\n", + "\n", + "Mit geschweiften Klammern können Platzhalter in Strings eingesetzt werden:\n", + "\n", + "(mehr Details: )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ccb62994", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Das folgende Wort wird ersetzt: '{}' Der Rest nicht.\".format(\"blargh\"))\n", + "print(\n", + " \"Das folgende Wort wird ersetzt: '{} und {}' Der Rest nicht.\".format(\"foo\", \"bar\")\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "f8304b68", + "metadata": {}, + "source": [ + "## Aufspalten\n", + "\n", + "Mit `.split` lassen sich Strings an einem Trennzeichen aufspalten:\n", + "Damit lässt sich ein einfacher (aber fehleranfälliger) CSV-Parser bauen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e6c1bb7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['a', 'b', 'cd']\n", + "a;b;cd\n" + ] + } + ], + "source": [ + "s = \"a;b;cd\"\n", + "l = s.split(\";\")\n", + "print(repr(l))\n", + "print(\";\".join(l))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git "a/Level_05/L\303\266sungen/fakultaet.py" "b/Level_05/L\303\266sungen/fakultaet.py" new file mode 100755 index 0000000..6c11a23 --- /dev/null +++ "b/Level_05/L\303\266sungen/fakultaet.py" @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 + +# Dies ist eine Beispiellösung für die erste Aufgabe des fünften Levels: + +def fakultaet(n): + # Alternativ: n == 0 + if n == 1: + return 1 + else: # Der else-Zweig kann auch weggelassen werden + return n * fakultaet(n-1) + +n = input("Bitte geben Sie eine Zahl ein: ") +if n.isdigit(): + n = int(n) + print(fakultaet(n)) diff --git a/Level_05/README.md b/Level_05/README.md new file mode 100644 index 0000000..422cd1a --- /dev/null +++ b/Level_05/README.md @@ -0,0 +1,12 @@ +# Level 5 Aufgaben +Wie bereits in den Aufgaben zu Level 3 angekündigt bieten Funktionen eine weitere Möglichkeit Abläufe zu wiederholen. Im Gegensatz zu den Schleifen sind die Einsatzmöglichkeiten von Funktionen weitaus vielfältiger. + +## Aufgabe 1: Fakultät rekursiv +Die Fakultät ist als rekursive Funktion definiert, weshalb es intuitiv sein sollte, sie als rekursive Funktion zu implementieren. In dieser Aufgabe geht es genau um diese Implementation. Schreibe eine Funktion `factorial(n: int) -> int` die eine Zahl `n` entgegen nimmt und rekursiv deren Fakultät berechnet. +Zur Erinnerung: Die Fakultät einer Zahl `n` ist gegeben durch: +``` +n! = n * (n-1) mit 0! = 1 +``` + +**Hinweis:** +Während es bei der while-Schleife keine Begrenzung gibt, was die maximale Anzahl an Durchläufen angeht, existiert für die Tiefe einer Rekursion ein Limit. diff --git a/Level_05/funktionen.py b/Level_05/funktionen.py deleted file mode 100755 index b582390..0000000 --- a/Level_05/funktionen.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python3 - -# Funktionen: - -def funktion(): - print("Hallo!") -funktion() -# OUT: Hallo! - - -def funktion(text): - print(text) -funktion("a") -# OUT: a - - -def funktion(text, wirklich): - if wirklich: - print(text) - -funktion("Hallo", True) -# OUT: Hallo - -funktion(True, "Hallo") -# OUT: True - - -def funktion(text="Beispiel", wirklich=False): - if wirklich: - print(text) - -funktion() -# OUT: None - -funktion(wirklich=True) -# OUT: Beispiel - -funktion(wirklich=True, text="Abc") -# OUT: Abc - - -def ja(): - return "Ja" -ja() -# OUT: 'Ja' - - -# Rekursion: - -def fun(): - print("Fun!") - fun() - -# Quersumme: -def quersumme(zahl): - qs = 0 - for ziffer in str(zahl): - qs += int(ziffer) - return qs diff --git a/Level_05/strings_erweitert.py b/Level_05/strings_erweitert.py deleted file mode 100755 index 36facf0..0000000 --- a/Level_05/strings_erweitert.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python3 - -# Character escaping: -# escaping ist eine Möglichkeit Zeichen und Steuerzeichen (z.B. \n und \t) in einen -# String einzubauen -print("Tab:\t#") - -# Das Zeichen hinter einem \ wird entweder Steuerzeichen interpretiert oder ignoriert -print("\aabc") - -# Folglich kann ein \ nicht trivial in einen String gepackt werden: -# Nicht so: -print("\0/") -# Sondern so: -print("\\0/") - -# Rawstrings können kein escaping: -print(r"\n") -print(r"\0/") - - -# string.format() -print("Das folgende Wort wird ersetzt: '{}' Der Rest nicht.".format("blargh")) -# Auch: -print("Das folgende Wort wird ersetzt: '{0} und {1}' Der Rest nicht.".format("foo", "bar")) - -# String.split() -s = "a;b;cd" -l = s.split(";") -print(repr(l)) -# l entspricht nun: ["a", "b", "cd"] -# Geeignet zum Parsen von .csv Dateien zum Beispiel - -s = ";".join(l) -# l enspricht nun: 'a;b;cd' - -# Wiederholung: -# string.split(char) Trennt den String bei jedem Auftreten von char -# string.join(list) Trennt die Liste mit String und gibt einen String zurück diff --git a/Level_05/zeit.py b/Level_05/zeit.py deleted file mode 100755 index a77e869..0000000 --- a/Level_05/zeit.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python3 -import sys -import time - -# Timestamp: -time.time() -# OUT: 1444327310.2887266 - - -# Datum und Uhrzeit: -time.localtime() -# OUT: time.struct_time(tm_year=2015, tm_mon=10, tm_mday=8, tm_hour=20, -# tm_min=2, tm_sec=11, tm_wday=3, tm_yday=281, tm_isdst=1) - -# Zugriff über Index -time.localtime()[0] -# OUT: 2015 - -list(time.localtime()) -# OUT: [2015, 10, 8, 20, 3, 1, 3, 281, 1] - -# Zugriff über Schlüssel -time.localtime().tm_year -# OUT: 2015 - - -# Pause: -time.sleep(1) -# Wartet eine Sekunde - - -# Ladebalken: - -import time -while True: - print(".", end="") - sys.stdout.flush() - time.sleep(1) -# OUT: ........................................... diff --git a/Level_06/README.md b/Level_06/README.md new file mode 100644 index 0000000..b55385a --- /dev/null +++ b/Level_06/README.md @@ -0,0 +1,18 @@ +# Level 6 Aufgaben + +## Aufgabe 1 (Monty Python) + +Passe deine Lösung aus Level 4 so an, dass: + * alle Dateinamen als Parameter auf der Kommandozeile übergeben werden können + * alle Befehle in einem Programm sind + * `argparse` dabei verwendet wird + +Wenn du keine eigene Lösung hast, kannst du auch unsere Lösung von Level 4 benutzen. +Aufrufbar sein soll das Programm am Ende wie folgt: + +```bash +python3 monty.py words --input monty.txt --output words.txt +python3 monty.py chars --input monty.txt --output chars.txt +python3 monty.py analyze --chars chars.txt +python3 monty.py replace --input monty.txt --output MONTY.txt +``` diff --git a/Level_06/add.py b/Level_06/add.py new file mode 100755 index 0000000..6545557 --- /dev/null +++ b/Level_06/add.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 +from sys import argv + +if len(argv) != 3: + print(f"Aufruf: {argv[0]} a b") + exit(1) + +a = int(argv[1]) +b = int(argv[2]) +c = a + b +print(f"{a} + {b} = {c}") diff --git a/Level_06/argv.py b/Level_06/argv.py new file mode 100755 index 0000000..b2f7176 --- /dev/null +++ b/Level_06/argv.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +from sys import argv +print(type(argv)) +print(argv) + +print(f"Programmname: {argv[0]}") diff --git a/Level_06/calc.py b/Level_06/calc.py new file mode 100755 index 0000000..6cccf3c --- /dev/null +++ b/Level_06/calc.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +"""Berechnet Dinge.""" + +from argparse import ArgumentParser + + +def op_add(a: int, b: int) -> int: + """Addiert a und b.""" + return a + b + + +def op_sub(a: int, b: int) -> int: + """Subtrahiert b von a.""" + return a - b + + +def op_mult(a: int, b: int) -> int: + """Multipliziert a mit b.""" + return a * b + + +def op_div(a: int, b: int) -> float: + """Teilt a durch b.""" + return a / b + + +def op_exp(a: int, b: int) -> int: + """Potenziert a mit b.""" + return a ** b + + +def op_root(a: int, b: int) -> float: + """Berechnet die a-te Wurzel von b.""" + return b ** (1 / a) + + +parser = ArgumentParser(description=__doc__) +subparsers = parser.add_subparsers( + dest="command", + help="die auszuführende Rechenoperation" +) +subparsers.required = True + +for function in ( + op_add, + op_sub, + op_mult, + op_div, + op_exp, + op_root, +): + parser_func = subparsers.add_parser( + function.__name__.lstrip("op_"), + help=function.__doc__ + ) + parser_func.add_argument("a", help="erster Wert", type=int) + parser_func.add_argument("b", help="zweiter Wert", type=int) + parser_func.set_defaults(func=function) + +if __name__ == "__main__": + # Verarbeiten der Argumente + args = parser.parse_args() + # die tatsächliche Funktion aufrufen + res = args.func(args.a, args.b) + print(res) diff --git a/Level_06/color.py b/Level_06/color.py new file mode 100755 index 0000000..e8cfd71 --- /dev/null +++ b/Level_06/color.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +# huepy muss vorher installiert werden. +import huepy + +print(huepy.bold(huepy.red("red and bold"))) + +print(huepy.run("Starte...")) +print(huepy.info("Info!!")) +print(huepy.bad("Schlecht!")) +print(huepy.good("Gut!")) +input(huepy.que("Frage? ")) + +# mit Fortschritt: +from tqdm import tqdm + +for x in tqdm(range(5000000), desc=huepy.run("Dinge")): + pass + diff --git a/Level_06/dialoge.py b/Level_06/dialoge.py new file mode 100755 index 0000000..d63e858 --- /dev/null +++ b/Level_06/dialoge.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +# pythondialog (http://pythondialog.sourceforge.net/doc/) muss vorher installiert. + +from dialog import Dialog + +d = Dialog() # für Grafik: Dialog("gdialog", compat="Xdialog") + +d.set_background_title("pythonfooLite") + +# Messagebox +d.msgbox("Hallo Welt!") + +# Auswahl +d.menu( + "Irgendwelcher Text", + choices={"id1": "Beschreibung", "id2": "Beschreibung"}.items(), + title="Schwere Auswahl" +) + +# vollständige Doku: http://pythondialog.sourceforge.net/doc/widgets.html diff --git a/Level_06/progress.py b/Level_06/progress.py new file mode 100755 index 0000000..111d0e7 --- /dev/null +++ b/Level_06/progress.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +from time import sleep + +# tqdm muss erst installiert werden. +from tqdm import tqdm, tqdm_gui + +print("feste Länge:") +for x in tqdm(range(25000000)): + pass + +print("unbekannte Länge:") +for x in tqdm(x for x in range(25000000)): + pass + +print("grafisch:") +for x in tqdm_gui(range(25000000)): + pass + +print("manuell:") +progress = tqdm(total=20) +for x in range(20): + sleep(1) + progress.update() # Standard-Schrittweite: 1 +progress.close() + +print("manuell mit with:") +with tqdm(total=10) as progress: # with wird später erklärt. + for x in range(20): + sleep(0.5) + progress.update(n=0.5) + +print("geschachtelt:") +for x in tqdm(range(50)): + for y in tqdm(range(1000)): + sleep(0.001) diff --git a/Level_06/OOP1.py b/Level_07/OOP1.py similarity index 70% rename from Level_06/OOP1.py rename to Level_07/OOP1.py index a1be5a4..f87e727 100755 --- a/Level_06/OOP1.py +++ b/Level_07/OOP1.py @@ -7,10 +7,10 @@ class Simple: Dies ist die einfachst mögliche Klasse. Sie hat keine Methoden, keine Attribute und erbt (implizit) von `object`. - + Sie ist allerdings relativ langweilig, weil man recht wenig mit ihr machen kann. - + Klassennamen sollten laut PEP8 in CamelCase sein und mit einem Großbuchstaben beginnen (https://www.python.org/dev/peps/pep-0008/#class-names). @@ -22,7 +22,7 @@ class HelloWorld: def hello_world(): """ Diese Methode gibt "Hello World!" auf der Konsole aus. - + Funktions- oder Methodennamen sollten laut PEP8 kleingeschrieben werden und evtl. mit Unterstrichen getrennt sein (https://www.python.org/dev/peps/pep-0008/#function-names). @@ -33,12 +33,12 @@ def hello_world(): HelloWorld.hello_world() class Hello: - def hello(name="World"): + def hello(name: str = "World") -> None: """ Natürlich können Methoden auch Parameter haben. Dies funktioniert genau so wie bei Funktionen. """ - print("Hello, {}!".format(name)) + print(f"Hello, {name}!") # Die Methode aufrufen: Hello.hello(getuser()) @@ -49,7 +49,7 @@ class SpecialNumbers: Da dies hier Konstanten sind, sind ihre Namen großschrieben (https://www.python.org/dev/peps/pep-0008/#constants). """ - PI = 3.14 + PI = 3.14 # type: float E = 2.71 # Zugriff @@ -61,67 +61,77 @@ class SpecialNumbers: class Calculator: """ Diese Klasse hat zusätzlich zu den statischen Attributen - auch noch zwei Instanzmethoden. + auch noch zwei statische Methoden. """ PI = 3.14 E = 2.71 - def multiply_by_pi(self, number): + @classmethod + def multiply_by_pi(cls, number): """ - Dies ist eine Instanzmethode. - Dies lässt sich daran erkennen, dass der erste Parameter `self` ist. - Dieses `self` ist eine Referenz auf das aktuelle Objekt. + Dies ist eine statische Methode mit Klassenreferenz. + Dies lässt sich daran erkennen, dass der erste Parameter `cls` ist + und an dem Dekorator `@classmethod`. + Dieses `cls` ist eine Referenz auf die Klasse. Da Variablennamen nur innerhalb von Funktionen und Modulen aufgelöst werden, ist dies nötig. """ - return number * self.PI + return number * cls.PI - def multiply_by_e(self, number): - return number * self.E + @classmethod + def multiply_by_e(cls, number): + return number * cls.E -c = Calculator() # Instanziierung -print(c.multiply_by_pi(5)) # Aufruf der Methode -# Achtung: Was nicht funktioniert: Calculator.multiply_by_pi(5) +print(Calculator.multiply_by_pi(5)) # Aufruf der Methode class Thing: """ Auch dies ist wieder eine ziemlich nutzlose Klasse. Aber sie hat einen Konstruktor! """ - def __init__(self): + def __init__(self) -> None: """ Dies ist ein Konstruktor. - Bis auf den Namen ähnelt er anderen Instanzmethoden. + Bis auf den Namen ähnelt er anderen Instanz-Methoden. Er wird aufgerufen, wenn die Klasse instanziert wird. - + Standardmäßig existiert ein leerer Konstruktor ohne Parameter. """ print ("Hallo!") Thing() # Instanziierung +# Ab Python 3.7 kann man hierfür auch dataclasses benutzen: +# https://docs.python.org/3/library/dataclasses.html class Contact: """ Ein Adressbucheintrag. """ - def __init__(self, name, phone, email): + def __init__(self, name: str, phone: int, email: str) -> None: """ Dies ist ein Konstruktor. Aber dieser hat Parameter. - + Diese Parameter werden Instanzvariablen zugewiesen. """ self.name = name self.phone = phone self.email = email + def print(self): + """ + Druckt den Kontakt aus. + """ + print(f"Name: {self.name}") + print(f"Telefonnummer: {self.phone}") + print(f"E-Mail: {self.email}") + + c = Contact("Ich", "01234-56789", "mail@example.org") -print("Name: {}".format(c.name)) -print("Telefonnummer: {}".format(c.phone)) -print("E-Mail: {}".format(c.email)) +c.print() class HTTPURL: """ Diese Klasse repräsentiert eine HTTPURL. """ - def __init__(self, url): + def __init__(self, url: str) -> None: self.url = url - - def open(self): + + def open(self) -> None: webbrowser.open(self.url) diff --git a/Level_07/OOP2.py b/Level_07/OOP2.py new file mode 100755 index 0000000..1045b6b --- /dev/null +++ b/Level_07/OOP2.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +""" +Dies ist ein Beispiel für Vererbung. + +Wir implementieren hier die komplexen Zahlen, +indem wir von der abstrakten Klasse numbers.Complex erben +und die relevanten Methoden schreiben. + +(Wenn man einfach nur mit komplexen Zahlen rechnen möchte, +ist dieser Aufwand nicht nötig oder sinnvoll. +`complex` ist bereits in der Standardbibliothek enthalten.) + +Siehe auch https://docs.python.org/3.7/library/numbers.html. + +Abstrakte Klassen kann man auch selber definieren, siehe dazu: +https://docs.python.org/3/library/abc.html + +Bei den Rückgabetypen ist `C` in Anführungszeichen gefasst, +weil der Typ zu den Zeitpunkt noch nicht definiert ist. +(Ab Python 3.7 wäre das nicht mehr nötig, siehe dazu PEP 563.) +""" + +from numbers import Complex +from math import sqrt + +__all__ = ["C"] + +class C(Complex): + """ + Komplexe Zahlen haben einen Real- und einen Imaginärteil. + + Sie werden häufig als a + bi geschrieben, + wobei a der Realteil und b der Imaginärteil ist. + + Man kann sie sich auch als zweidimensionalen Vektorraum vorstellen, der 1 + 0i (bzw. (1, 0)) und 0 + 1i (bzw. (0, 1)) als Basisvektoren hat, d.h. eine Dimension ist der Realteil und die andere Dimension ist der Imaginärteil + """ + real = 0 # type: float + imag = 0 # type: float + + def __init__(self, real: float = 0, imag: float = 0) -> None: + """ + Erstellt eine neue komplexe Zahl. + + Sowohl Real- als auch Imaginärteil können weggelassen werden, + dann wird einfach 0 angenommen. + """ + self.real = real + self.imag = imag + + def __abs__(self) -> float: + """ + Berechnet den Betrag einer komplexen Zahl.abs + + Mit der Vektordarstellung (real, imag) sollte das klar sein + - das ist nur der Satz von Pythagoras. + """ + return sqrt(self.real**2 + self.imag**2) + + def __add__(self, o: Complex) -> "C": + """ + Addiert zwei komplexe Zahlen. + + Mit der Vektordarstellung sollte das klar sein: + g = (a, b), h = (c, d), g + h = (a + c, b + d) + """ + assert isinstance(o, Complex) + return C(self.real + o.real, self.imag + o.imag) + + def __radd__(self, o: float) -> "C": + """ + Addiert eine rationale Zahl zu einer komplexen Zahl. + + Hierbei ändert sich einfach nur der Realteil. + """ + assert isinstance(o, float) + return C(self.real + o, self.imag) + + def __mul__(self, o: Complex) -> "C": + """ + Multipliziert zwei komplexe Zahlen. + """ + assert isinstance(o, Complex) + return C( + real=self.real * o.real - self.imag * o.imag, + imag=self.real * o.imag + self.imag * o.real + ) + + def __rmul__(self, o: float) -> "C": + """ + Multipliziert eine rationale Zahl an eine komplexe Zahl. + + Hierbei ändert sich nur der Realteil. + """ + assert isinstance(o, float) + return C(self.real * o, self.imag) + + def __pow__(self, o: int) -> "C": + """ + Potenziert eine komplexe Zahl. + """ + assert o >= 0 + value = C(1, 1) + for i in range(o): + value *= self + return value + + def __rpow__(self, o: float) -> "C": + """ + Potenziert nur den Realteil. + """ + return C(self.real ** o, self.imag) + + def __truediv__(self, o: Complex) -> "C": + """ + Dividiert zwei komplexe Zahlen. + """ + assert isinstance(o, Complex) + return C( + real=(self.real * o.real + self.imag * o.imag) / (o.real ** 2 + o.imag ** 2), + imag=(self.imag * o.real - self.real * o.imag) / (o.real ** 2 + o.imag ** 2) + ) + + def __rtruediv__(self, o: float) -> "C": + """ + Dividiert eine komplexe Zahl durch eine rationale Zahl. + + Hierbei ändert sich nur der Realteil. + """ + return C(self.real / o, self.imag) + + def __eq__(self, o: object) -> bool: + """ + Vergleicht zwei komplexe Zahlen auf Äquivalenz. + + Mit der Vektordarstellung sollte das klar sein: + g = (a, b), h = (c, d), (g = h) <=> (a = c ^ b = c) + """ + if not isinstance(o, Complex): + return False + return (self.real == o.real) and (self.imag == o.imag) + + def conjugate(self) -> "C": + """ + Berechnet das komplexe Konjugat einer komplexen Zahl. + """ + return C(self.real, -self.imag) + + def __pos__(self) -> "C": + """ + Berechnet +x (für x eine komplexe Zahl). + """ + return self + + def __neg__(self) -> "C": + """ + Berechnet -x (für x eine komplexe Zahl). + """ + return C(-self.real, -self.imag) + + def __complex__(self) -> complex: + """ + Wandelt eine komplexe Zahl in eine complex-Instanz um. + """ + return complex(self.real, self.imag) + + def __hash__(self) -> int: + """ + Berechnet den Hashwert einer komplexen Zahl. + + Wichtig ist: Wenn zwei Zahlen äquivalent sind, sollen sie den gleichen Hash haben. + + Wir machen es uns einfach und nehmen einfach die menschen-lesbare Darstellung. + """ + return hash(repr(self)) + + def __repr__(self) -> str: + """ + Stellt eine komplexe Zahl menschen-lesbar dar. + + Dies gibt die Darstellung a + b i, + nicht die Vektordarstellung (a, b) zurück. + """ + if self.imag >= 0: + fstr = "{} + {}i" + else: + fstr = "{} - {}i" + return fstr.format(self.real, self.imag) + +if __name__ == "__main__": + # Hier könnte Code stehen. + pass diff --git a/Level_06/Ueberladung.py b/Level_07/Ueberladung.py similarity index 74% rename from Level_06/Ueberladung.py rename to Level_07/Ueberladung.py index db96474..0a150fe 100644 --- a/Level_06/Ueberladung.py +++ b/Level_07/Ueberladung.py @@ -1,42 +1,42 @@ -""" Diese Datei zeigt Operatorüberladung. """ +""" Diese Datei zeigt Operator-Überladung. """ import math class Punkt: """ Ein Punkt in einem dreidimensionalen Koordinatensystem. - + Man kann ihn z.B. ausgeben lassen, vergleichen oder addieren. """ - - def __init__(self, x, y, z): + + def __init__(self, x, y, z) -> None: """ Ein Punkt wird erzeugt unter Angabe von drei Koordinaten: x, y und z. """ self.x = float(x) self.y = float(y) self.z = float(z) - - def __repr__(self): - """ die menschenlesbare Darstellung -- str und repr """ - return "({}|{}|{})".format(self.x, self.y, self.z) - - def __eq__(self, p): + + def __repr__(self) -> str: + """ die menschen-lesbare Darstellung -- str und repr """ + return f"({self.x}|{self.y}|{self.z})" + + def __eq__(self, p: "Punkt") -> bool: """ prüft auf Äquivalenz -- == """ if hasattr(p, "x") and hasattr(p, "y") and hasattr(p, "z"): return self.x == p.x and self.y == p.y and self.z == p.z else: return False - - def __add__(self, p): + + def __add__(self, p: "Punkt") -> "Punkt": """ addiert p und erzeugt einen neuen Punkt -- + """ assert isinstance(p, Punkt) return Punkt(self.x + p.x, self.y + p.y, self.z + p.z) - - def __sub__(self, p): + + def __sub__(self, p: "Punkt") -> "Punkt": """ subtrahiert p und erzeugt einen neuen Punkt -- - """ assert isinstance(p, Punkt) return self + -p - - def __neg__(self): + + def __neg__(self) -> "Punkt": """ negiert dieses Objekt -- - """ return Punkt(-self.x, -self.y, -self.z) @@ -45,22 +45,22 @@ class Strecke: Eine Strecke ist eine Linie zwischen zwei Punkten. Sie hat keine Richtung. """ - - def __init__(self, p1, p2): + + def __init__(self, p1: Punkt, p2: Punkt) -> None: """ Eine Strecke wird erzeugt unter Angabe zweier Punkte. """ assert isinstance(p1, Punkt) assert isinstance(p2, Punkt) self.p1 = p1 self.p2 = p2 - - def __repr__(self): - """ die menschenlesbare Darstellung -- str und repr """ - return "{} - {}".format(self.p1, self.p2) - - def __eq__(self, l): + + def __repr__(self) -> str: + """ die menschen-lesbare Darstellung -- str und repr """ + return f"{self.p1} - {self.p2}" + + def __eq__(self, l: "Strecke") -> bool: """ prüft auf Äquivalenz -- == - + Strecken haben keine Reihenfolge. """ if not isinstance(l, Strecke): @@ -70,42 +70,42 @@ def __eq__(self, l): if self.p1 == l.p2 and self.p2 == l.p1: return True return False - - def __abs__(self): + + def __abs__(self) -> float: """ berechnet den Betrag -- abs """ x = self.p1.x - self.p2.x y = self.p1.y - self.p2.y z = self.p1.z - self.p2.z return math.sqrt(x**2 + y**2 + z**2) - - def __len__(self): + + def __len__(self) -> int: """ Berechnet die Länge. Dies muss ein int sein. -- len """ return int(abs(self)) - - def __gt__(self, l): + + def __gt__(self, l: "Strecke") -> bool: """ prüft auf echtes größer -- > - + Dies muss ein bool zurückgeben. - + kleiner muss nicht manuell implementiert werden. """ return abs(self) > abs(l) - - def __ge__(self, l): + + def __ge__(self, l: "Strecke") -> bool: """ prüft auf größer oder gleich -- >= - + Dies muss ein bool zurückgeben. - + kleiner gleich muss nicht manuell implementiert werden. """ return self == l or self > l class Vektor: """ Ein Vektor hat eine Richtung. """ - - def __init__(self, *args): + + def __init__(self, *args) -> None: if len(args) == 3: # x, y, z self.x = float(args[0]) self.y = float(args[1]) @@ -116,44 +116,44 @@ def __init__(self, *args): self.z = args[1].z - args[0].z else: raise NotImplementedError - - def __repr__(self): - """ die menschenlesbare Darstellung -- str und repr """ - return "({}|{}|{})".format(self.x, self.y, self.z) - - def __eq__(self, l): + + def __repr__(self) -> str: + """ die menschen-lesbare Darstellung -- str und repr """ + return f"({self.x}|{self.y}|{self.z})" + + def __eq__(self, l: "Vektor") -> bool: """ Äquivalenz: Vektoren haben eine Richtung. """ if not isinstance(l, Vektor): return False return self.x == l.x and self.y == l.y and self.z == l.z - - def __abs__(self): + + def __abs__(self) -> float: """ berechnet den Betrag -- abs """ return math.sqrt(self.x**2 + self.y**2 + self.z**2) - - def __len__(self): + + def __len__(self) -> int: return int(abs(self)) - - def __gt__(self, l): + + def __gt__(self, l: "Vektor") -> bool: return abs(self) > abs(l) - - def __ge__(self, l): + + def __ge__(self, l: "Vektor") -> bool: return self == l or self > l - - def __add__(self, l): + + def __add__(self, l: "Vektor") -> "Vektor": """ Addition """ assert isinstance(l, Vektor) return Vektor(self.x + l.x, self.y + l.y, self.z + l.z) - - def __sub__(self, l): + + def __sub__(self, l: "Vektor") -> "Vektor": """ Subtraktion """ assert isinstance(l, Vektor) return self + -l - - def __neg__(self): + + def __neg__(self) -> "Vektor": """ Negation """ return Vektor(-self.x, -self.y, -self.z) - + def __mul__(self, faktor): """ Multiplikation """ if isinstance(faktor, float) or isinstance(faktor, int): @@ -161,7 +161,7 @@ def __mul__(self, faktor): x = self.x * faktor y = self.y * faktor z = self.z * faktor - return Vektor(self.p1, self.p1 + Punkt(x, y, z)) + return Vektor(x, y, z) if isinstance(faktor, Vektor): # Multiplikation mit einem Vektor ergibt einen Skalar. x = self.x * faktor.x @@ -169,8 +169,8 @@ def __mul__(self, faktor): z = self.z * faktor.z return x + y + z return None - - def __pow__(self, exp): + + def __pow__(self, exp: int): """ Potenzieren - ** """ assert isinstance(exp, int) assert exp > 0 @@ -178,14 +178,13 @@ def __pow__(self, exp): for i in range(0, exp): r *= r return r - + def __iter__(self): """ Iterator - siehe nächstes Kapitel """ yield self.x yield self.y yield self.z - - def __getitem__(self, item): + + def __getitem__(self, item: int) -> float: """ Zugriff via Index """ return tuple(self)[item] - diff --git a/Level_07/exceptions.py b/Level_07/exceptions.py deleted file mode 100755 index 396312c..0000000 --- a/Level_07/exceptions.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 - -# Exceptions -try: - 1 / 0 - -except ZeroDivisionError as exc: - print(exc) - -finally: - print("Fertig.") - -# OUT: -# division by zero -# Fertig - -# Nett ist auch "raise" innerhalb eines except-Blocks. - -try: - x = input() - x = int(x) -except ValueError: - print(x, " kann nicht als Integer benutzt werden.") - raise -else: - print("Kein Valuefehler") - -# So wird der Fehler bearbeitet, aber der Fehler bleibt nicht unentdeckt - diff --git a/Level_07/fight.py b/Level_07/fight.py new file mode 100644 index 0000000..2ef6b20 --- /dev/null +++ b/Level_07/fight.py @@ -0,0 +1,70 @@ +from typing import Optional + +class Weapon: + name: str + damage: int + + def __init__(self: "Weapon", init_name: str, init_damage: int): + self.name = init_name + self.damage = init_damage + + def __repr__(self: "Weapon") -> str: + return "Weapon(name=" + self.name + ", damage=" + str(self.damage) + ")" + +class Supplement: + name: str + healing: int + + def __init__(self: "Supplement", name: str, healing: int): + self.name = name + self.healing = healing + + def __repr__(self: "Supplement") -> str: + return "Supplement(name=" + self.name + ", healing=" + str(self.healing) + ")" + +class Character: + name: str + health: int + + def __init__(self: "Character", name: str, health: int): + self.name = name + self.health = health + + def take(self: "Character", supplement: Supplement): + self.health += supplement.healing + +class Monster(Character): + def __init__(self: "Monster", name: str, health: int = 5): + super().__init__(name, health) + + def __repr__(self: "Monster") -> str: + return "Monster(name=" + self.name + ", health=" + str(self.health) + ")" + +class Player(Character): + """A fearless wanderer, ready to attack.""" + weapon: Optional[Weapon] = None + + def __init__(self: "Player", name: str, health: int = 10): + super().__init__(name, health) + + def __repr__(self: "Player") -> str: + return "Player(name=" + self.name + ", health=" + str(self.health) + ", weapon=" + repr(self.weapon) + ")" + + def attack(self: "Player", other: "Player | Monster"): + if self.weapon is None: + other.health -= 1 + else: + other.health -= self.weapon.damage + +class Villager(Character): + def __init__(self: "Villager", name: str): + super().__init__(name, 9) + +hero = Player("Hero") +orky = Monster("Orky") +sword = Weapon("Sword", 3) +hero.weapon = sword +hugo = Villager("Hugo Müller") +hero.attack(hugo) +heiltrank = Supplement("Donnergurgler", 10) + diff --git a/Level_07/generatoren.py b/Level_07/generatoren.py deleted file mode 100755 index b7aec01..0000000 --- a/Level_07/generatoren.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python3 - -# Generatoren und yield -def gen(s): - for char in s: - yield char - - -for x in gen("abcdef"): - print(x) - -# Dekoratoren -def f(x): - return x**2 - - -# IN: f(2) -# OUT: 4 -# IN: f(3) -# OUT: 9 - -def dec(func): - def inner_func(*args): - print(args) - r = func(*args) - print("Return: {}".format(r)) - return r - return inner_func - -@dec -def f(x): - return x**2 - - -# IN: f(2) -# OUT: (2,) -# OUT: Return: -# OUT: 4 -# OUT:4 diff --git a/Level_07/linalg/gruppen.py b/Level_07/linalg/gruppen.py new file mode 100644 index 0000000..15ce3e2 --- /dev/null +++ b/Level_07/linalg/gruppen.py @@ -0,0 +1,31 @@ +from abc import ABC, abstractmethod +from typing import Optional + +class Gruppe(ABC): + neutral = None # type: Optional[Gruppe] + + @abstractmethod + def __init__(self, value: "Gruppe") -> None: + pass + + @abstractmethod + def __mul__(self, other: "Gruppe") -> "Gruppe": + pass + + @abstractmethod + def __inv__(self) -> "Gruppe": + pass + +class Z_plus(Gruppe): + neutral = Z_plus(0) + + def __init__(self, value: int) -> None: + assert isinstance(value, int) + self.value = value + + def __mul__(self, other: Z_plus) -> Z_plus: + assert isinstance(other, Z_plus) + return Z_plus(self.value + other.value) + + def __inv__(self) -> Z_plus: + return Z_plus(-self.value) diff --git a/Level_07/map.py b/Level_07/map.py deleted file mode 100755 index f0c12d5..0000000 --- a/Level_07/map.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python3 - -# map - -def add_2(x): - return x + 2 - -l = range(10) - -# Statt: -result = [] -for i in l: - result.append(add_2(i)) - -# Kann man map() benutzen: -result = list(map(add_2, l)) - - diff --git a/Level_07/with.py b/Level_07/with.py deleted file mode 100755 index 9b80201..0000000 --- a/Level_07/with.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python3 - -""" -with ist ein Kontextmanager. - -Eine genauere Beschreibung als hier findet sich unter https://docs.python.org/3.6/reference/compound_stmts.html#with und https://docs.python.org/3.6/reference/datamodel.html#context-managers . - -Hier folgen nun einige Beispiele. -""" - -# Dateien öffnen - -with open("../Level_04/loremipsum.txt", "r") as lorem: - print(lorem.read()) - -# Exceptions ignorieren - -from contextlib import suppress - -with suppress(ZeroDivisionError): - print(1/0) - -# temporäre Dateien und Ordner - -import tempfile -from os.path import join - -with tempfile.TemporaryFile(mode="w") as tmpfile: - tmpfile.write("Dies ist ein Test.\n") - -with tempfile.TemporaryDirectory() as tmpdir: - with open(join(tmpdir, "test.txt"), "w") as test: - test.write("Dies ist auch ein Test.\n") diff --git a/Level_08/Beispielcode/fibonacci.py b/Level_08/Beispielcode/fibonacci.py new file mode 100755 index 0000000..a3b0f4a --- /dev/null +++ b/Level_08/Beispielcode/fibonacci.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +""" +Dieses Programm berechnet die Fibonacci-Reihe rekursiv (siehe Level 5). +Dabei werden aber die Zwischenergebnisse gecachet. +""" + +def cache(func): + """ + Dies ist ein Dekorator der Funktionsaufrufe cachet. + Er funktioniert natürlich nur sinnvoll für mathematische Funktionen, + also Funktionen, die beim Aufruf mit den gleichen Parametern immer das gleiche Ergebnis zurückliefern und sonst keine Seiteneffekte haben. + + Dieser Cache hat keinerlei Ersetzungs- oder Löschstrategien, wird also mit der Zeit immer größer. + Das ist nicht ideal, reicht aber für dieses Beispiel. + """ + # ein Dict erzeugen für die zwischengespeicherten Werte + values = dict() + + # die neue Funktion + # hier der Einfachheit halber nur positionale Parameter + def new_func(*args): + # Ist der Wert schon berechnet worden? + if args in values.keys(): + # dann gebe das Ergebnis zurück + return values[args] + # Ansonsten müssen wir die Funktion aufrufen und das Ergebnis speichern. + result = func(*args) + values[args] = result + return result + + return new_func + +# die gleiche nicht-performante Version von Fibonacci wie in Level 5 +@cache +def fib(n: int) -> int: + if n <= 1: + return n + return fib(n-1) + fib(n-2) + +n = int(input("Welches Element soll berechnet werden? ")) +print(" =>", fib(n)) diff --git a/Level_08/Beispielcode/fizzbuzz_func.py b/Level_08/Beispielcode/fizzbuzz_func.py new file mode 100644 index 0000000..325c4ff --- /dev/null +++ b/Level_08/Beispielcode/fizzbuzz_func.py @@ -0,0 +1,23 @@ +# funktionales FizzBuzz + +# entweder: +list(map( + print, + map( + lambda t: ( + (not t % 3)*"fizz" + (not t % 5) * "buzz" + ) or str(t), + range(1, 101) + ) +)) + + +# oder: +[ + print( + ( + (not t % 3)*"fizz" + (not t % 5) * "buzz" + ) or str(t) + ) + for t in range(1, 101) +] diff --git a/Level_08/Beispielcode/fizzbuzz_iter.py b/Level_08/Beispielcode/fizzbuzz_iter.py new file mode 100644 index 0000000..36dc265 --- /dev/null +++ b/Level_08/Beispielcode/fizzbuzz_iter.py @@ -0,0 +1,10 @@ +def fizz_buzz(number: int) -> str: + output = "" + if number % 3 == 0: + output += "fizz" + if number % 5 == 0: + output += "buzz" + return output or str(number) + +for val in map(fizz_buzz, range(1, 16)): + print(val) diff --git a/Level_08/Level_8.ipynb b/Level_08/Level_8.ipynb new file mode 100644 index 0000000..67cae1d --- /dev/null +++ b/Level_08/Level_8.ipynb @@ -0,0 +1,695 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "cd0bab55", + "metadata": {}, + "source": [ + "# Exceptions\n", + "\n", + "Bisher ist unser Programm abgestürzt, wenn Fehler auftreten. Das muss nicht passieren:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "1243337c", + "metadata": {}, + "outputs": [ + { + "ename": "ZeroDivisionError", + "evalue": "division by zero", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[5], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;241;43m1\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m/\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\n", + "\u001b[0;31mZeroDivisionError\u001b[0m: division by zero" + ] + } + ], + "source": [ + "1 / 0" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c8d4962e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "division by zero\n", + "Fertig.\n" + ] + } + ], + "source": [ + "try:\n", + " 1 / 0\n", + "\n", + "except ZeroDivisionError as exc:\n", + " print(exc)\n", + "\n", + "finally:\n", + " print(\"Fertig.\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "6d40ff35", + "metadata": {}, + "source": [ + "Schön ist auch `raise` innerhalb eines `except`-Blocks.\n", + "\n", + "So wird der Fehler bearbeitet, aber bleibt nicht unentdeckt:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "f9e8689d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a kann nicht als Integer benutzt werden.\n" + ] + }, + { + "ename": "ValueError", + "evalue": "invalid literal for int() with base 10: 'a'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[7], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 2\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;28minput\u001b[39m()\n\u001b[0;32m----> 3\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mint\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m:\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28mprint\u001b[39m(x, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mkann nicht als Integer benutzt werden.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[0;31mValueError\u001b[0m: invalid literal for int() with base 10: 'a'" + ] + } + ], + "source": [ + "try:\n", + " x = input()\n", + " x = int(x)\n", + "except ValueError:\n", + " print(x, \"kann nicht als Integer benutzt werden.\")\n", + " raise\n", + "else:\n", + " print(\"Kein Value-Fehler\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "0631e2b4", + "metadata": {}, + "source": [ + "Man kann auch eigene Fehler definieren, die von Exception erben:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "747ab3fa", + "metadata": {}, + "outputs": [ + { + "ename": "MeinFehler", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mMeinFehler\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[8], line 4\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mclass\u001b[39;00m \u001b[38;5;21;01mMeinFehler\u001b[39;00m(\u001b[38;5;167;01mException\u001b[39;00m):\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mpass\u001b[39;00m\n\u001b[0;32m----> 4\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m MeinFehler\n", + "\u001b[0;31mMeinFehler\u001b[0m: " + ] + } + ], + "source": [ + "class MeinFehler(Exception):\n", + " pass\n", + "\n", + "raise MeinFehler" + ] + }, + { + "cell_type": "markdown", + "id": "e3ac0adb", + "metadata": {}, + "source": [ + "# with\n", + "\n", + "`with` ist ein sogenannter Kontextmanager.\n", + "\n", + "Eine genauere Beschreibung als hier findet sich unter und .\n", + "\n", + "Hier folgen nun einige Beispiele.\n", + "\n", + "## Dateien öffnen" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "a718b5e9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.\n", + "Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.\n", + "Suspendisse lectus leo, consectetur in tempor sit amet, placerat quis neque. Etiam luctus porttitor lorem, sed suscipit est rutrum non. Curabitur lobortis nisl a enim congue semper. Aenean commodo ultrices imperdiet. Vestibulum ut justo vel sapien venenatis tincidunt. Phasellus eget dolor sit amet ipsum dapibus condimentum vitae quis lectus. Aliquam ut massa in turpis dapibus convallis. Praesent elit lacus, vestibulum at malesuada et, ornare et est. Ut augue nunc, sodales ut euismod non, adipiscing vitae orci. Mauris ut placerat justo. Mauris in ultricies enim. Quisque nec est eleifend nulla ultrices egestas quis ut quam. Donec sollicitudin lectus a mauris pulvinar id aliquam urna cursus. Cras quis ligula sem, vel elementum mi. Phasellus non ullamcorper urna.\n", + "Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In euismod ultrices facilisis. Vestibulum porta sapien adipiscing augue congue id pretium lectus molestie. Proin quis dictum nisl. Morbi id quam sapien, sed vestibulum sem. Duis elementum rutrum mauris sed convallis. Proin vestibulum magna mi. Aenean tristique hendrerit magna, ac facilisis nulla hendrerit ut. Sed non tortor sodales quam auctor elementum. Donec hendrerit nunc eget elit pharetra pulvinar. Suspendisse id tempus tortor. Aenean luctus, elit commodo laoreet commodo, justo nisi consequat massa, sed vulputate quam urna quis eros. Donec vel. \n", + "\n" + ] + } + ], + "source": [ + "with open(\"../Level_04/Beispielcode/loremipsum.txt\") as lorem:\n", + " print(lorem.read())" + ] + }, + { + "cell_type": "markdown", + "id": "4573de3f", + "metadata": {}, + "source": [ + "## Exceptions ignorieren" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "75ef5391", + "metadata": {}, + "outputs": [], + "source": [ + "from contextlib import suppress\n", + "\n", + "with suppress(ZeroDivisionError):\n", + " print(1 / 0)" + ] + }, + { + "cell_type": "markdown", + "id": "e96478a9", + "metadata": {}, + "source": [ + "## temporäre Dateien und Ordner" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "0cdf805c", + "metadata": {}, + "outputs": [], + "source": [ + "import tempfile\n", + "from os.path import join\n", + "\n", + "with tempfile.TemporaryFile(mode=\"w\") as tmpfile:\n", + " tmpfile.write(\"Dies ist ein Test.\\n\")\n", + "\n", + "with tempfile.TemporaryDirectory() as tmpdir:\n", + " with open(join(tmpdir, \"test.txt\"), \"w\") as test:\n", + " test.write(\"Dies ist auch ein Test.\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "f69a7254", + "metadata": {}, + "source": [ + "contextlib bietet auch Dekoratoren an, um eigene Contextmanager zu erstellen:\n", + "" + ] + }, + { + "cell_type": "markdown", + "id": "9b383d6b", + "metadata": {}, + "source": [ + "# Generatoren\n", + "\n", + "Generatoren können \"lazy\" Elemente erzeugen:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "581b8844", + "metadata": {}, + "outputs": [], + "source": [ + "# Generatoren und yield\n", + "def gen(s):\n", + " for char in s:\n", + " yield char" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "a75ac011", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a\n", + "b\n", + "c\n", + "d\n", + "e\n", + "f\n" + ] + } + ], + "source": [ + "# iterieren mit einer for-Schleife:\n", + "for x in gen(\"abcdef\"):\n", + " print(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "8d4afc47", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "f\n", + "o\n" + ] + } + ], + "source": [ + "# oder manuell mit next:\n", + "g = gen(\"foobar\")\n", + "print(next(g))\n", + "print(next(g))" + ] + }, + { + "cell_type": "markdown", + "id": "4c7e69b4", + "metadata": {}, + "source": [ + "# Dekoratoren\n", + "\n", + "Dekoratoren sind Funktionen, die auf Funktionen angewandt werden bei deren Definition:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "d3ed8738", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4\n", + "9\n" + ] + } + ], + "source": [ + "def f(x):\n", + " return x**2\n", + "\n", + "print(f(2))\n", + "print(f(3))" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "a2bba8e0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Args: (2,)\n", + "Return: 4\n" + ] + }, + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def dec(func):\n", + " def inner_func(*args):\n", + " print(f\"Args: {args}\")\n", + " r = func(*args)\n", + " print(f\"Return: {r}\")\n", + " return r\n", + "\n", + " return inner_func\n", + "\n", + "\n", + "@dec\n", + "def f(x):\n", + " return x**2\n", + "\n", + "f(2)" + ] + }, + { + "cell_type": "markdown", + "id": "7abbcad7", + "metadata": {}, + "source": [ + "# map\n", + "\n", + "Mit `map` lassen sich Funktionen auf jedes Element eines Generators anwenden:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "9caff1aa", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def add_2(x):\n", + " return x + 2\n", + "\n", + "\n", + "l = range(10)\n", + "result = list(map(add_2, l))\n", + "result\n", + "\n", + "# äquivalent zum folgenden Code:\n", + "# result = []\n", + "# for i in l:\n", + "# result.append(add_2(i))\n", + "\n", + "# oder auch: result = [add_2(x) for x in l]" + ] + }, + { + "cell_type": "markdown", + "id": "f1b2b72d", + "metadata": {}, + "source": [ + "# filter\n", + "\n", + "`filter` funktioniert ähnlich, aber \"siebt\" die Elemente:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "ed19bc69", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0,\n", + " 2,\n", + " 4,\n", + " 6,\n", + " 8,\n", + " 10,\n", + " 12,\n", + " 14,\n", + " 16,\n", + " 18,\n", + " 20,\n", + " 22,\n", + " 24,\n", + " 26,\n", + " 28,\n", + " 30,\n", + " 32,\n", + " 34,\n", + " 36,\n", + " 38,\n", + " 40,\n", + " 42,\n", + " 44,\n", + " 46,\n", + " 48,\n", + " 50,\n", + " 52,\n", + " 54,\n", + " 56,\n", + " 58,\n", + " 60,\n", + " 62,\n", + " 64,\n", + " 66,\n", + " 68,\n", + " 70,\n", + " 72,\n", + " 74,\n", + " 76,\n", + " 78,\n", + " 80,\n", + " 82,\n", + " 84,\n", + " 86,\n", + " 88,\n", + " 90,\n", + " 92,\n", + " 94,\n", + " 96,\n", + " 98]" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def even(n):\n", + " return n % 2 == 0\n", + "\n", + "\n", + "r = range(100)\n", + "even_numbers = list(filter(even, r))\n", + "# oder: even_numbers = [x for x in r if even(x)]\n", + "even_numbers" + ] + }, + { + "cell_type": "markdown", + "id": "f53c24bb", + "metadata": {}, + "source": [ + "# zip\n", + "\n", + "`zip` fügt mehrere Iteratoren zusammen:" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "1c3cf39f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[(0, -10),\n", + " (1, -9),\n", + " (2, -8),\n", + " (3, -7),\n", + " (4, -6),\n", + " (5, -5),\n", + " (6, -4),\n", + " (7, -3),\n", + " (8, -2),\n", + " (9, -1)]" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "iter1 = range(10)\n", + "iter2 = range(-10, 0)\n", + "list(zip(iter1, iter2))" + ] + }, + { + "cell_type": "markdown", + "id": "491e268c", + "metadata": {}, + "source": [ + "# lambda\n", + "\n", + "Mit `lambda` lassen sich anonyme Funktionen definieren:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "92c56dea", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0,\n", + " 2,\n", + " 4,\n", + " 6,\n", + " 8,\n", + " 10,\n", + " 12,\n", + " 14,\n", + " 16,\n", + " 18,\n", + " 20,\n", + " 22,\n", + " 24,\n", + " 26,\n", + " 28,\n", + " 30,\n", + " 32,\n", + " 34,\n", + " 36,\n", + " 38,\n", + " 40,\n", + " 42,\n", + " 44,\n", + " 46,\n", + " 48,\n", + " 50,\n", + " 52,\n", + " 54,\n", + " 56,\n", + " 58,\n", + " 60,\n", + " 62,\n", + " 64,\n", + " 66,\n", + " 68,\n", + " 70,\n", + " 72,\n", + " 74,\n", + " 76,\n", + " 78,\n", + " 80,\n", + " 82,\n", + " 84,\n", + " 86,\n", + " 88,\n", + " 90,\n", + " 92,\n", + " 94,\n", + " 96,\n", + " 98]" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(filter(lambda x: x % 2 == 0, r))" + ] + }, + { + "cell_type": "markdown", + "id": "cf140ff2", + "metadata": {}, + "source": [ + "# all / any\n", + "\n", + "`all` und `any` laufen einen Iterator ab und prüfen Bedigungen, brechen aber ggf. früher ab:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "49dbeb10", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "all(even(x) for x in even_numbers)" + ] + }, + { + "cell_type": "markdown", + "id": "90fea9ed", + "metadata": {}, + "source": [ + "Für mehr Spaß mit Generatoren lohnt sich ein Blick auf [itertools](https://docs.python.org/3/library/itertools.html) und [more-itertools](https://more-itertools.readthedocs.io)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Level_08/async.py b/Level_09/async.py similarity index 82% rename from Level_08/async.py rename to Level_09/async.py index 674fc9b..77cf4d7 100755 --- a/Level_08/async.py +++ b/Level_09/async.py @@ -3,12 +3,10 @@ import string from sys import argv -# alternativ (ab Python 3.5): async def -@asyncio.coroutine -def print_string(mystring, wait=0.1): +async def print_string(mystring, wait=0.1): while True: print(mystring, end="", flush=True) - yield from asyncio.sleep(wait) # alternativ (ab Python 3.5): await + await asyncio.sleep(wait) """ Die Event-Loop ist bei asyncio sehr wichtig. diff --git a/Level_08/prozesse.py b/Level_09/prozesse.py similarity index 82% rename from Level_08/prozesse.py rename to Level_09/prozesse.py index c76a2ba..6640684 100755 --- a/Level_08/prozesse.py +++ b/Level_09/prozesse.py @@ -5,17 +5,17 @@ from sys import argv """ -multiprocessing ist progammatisch ähnlich zu verwenden wie threading. +multiprocessing ist programmatisch ähnlich zu verwenden wie threading. Das Modul heißt anders und die Klasse auch (nämlich Process). """ class PIDPrinter(Process): - def __init__(self, wait=0.1): + def __init__(self, wait: float = 0.1) -> None: Process.__init__(self) self.wait = wait self.daemon = True # siehe Threads - - def run(self): + + def run(self) -> None: while True: print(getpid()) sleep(self.wait) @@ -24,7 +24,7 @@ def run(self): Alternativ kann man auch einfach eine bestimmte Methode in einem neuen Prozess ausführen ohne eine neue Klasse zu schreiben: -def fun(): +def fun() -> None: pass Process(target=fun).start() diff --git a/Level_08/threads.py b/Level_09/threads.py similarity index 87% rename from Level_08/threads.py rename to Level_09/threads.py index 9aaa83f..103bbd4 100755 --- a/Level_08/threads.py +++ b/Level_09/threads.py @@ -14,13 +14,13 @@ """ class PrintThread(Thread): - def __init__(self, string, wait=0.1): + def __init__(self, string: str, wait: float = 0.1) -> None: Thread.__init__(self) self.string = string self.wait = wait - self.daemon = True # Soll dieser Thread beendet werden beim Programmende des Hauptthreads? - - def run(self): + self.daemon = True # Soll dieser Thread beendet werden beim Programmende des Haupt-Threads? + + def run(self) -> None: while True: print(self.string, end="", flush=True) sleep(self.wait) @@ -29,7 +29,7 @@ def run(self): Alternativ kann man auch einfach eine bestimmte Methode in einem neuen Thread ausführen ohne eine neue Klasse zu schreiben: -def fun(): +def fun() -> None: pass Thread(target=fun).start() diff --git a/Level_10/Level_10.ipynb b/Level_10/Level_10.ipynb new file mode 100644 index 0000000..37938d1 --- /dev/null +++ b/Level_10/Level_10.ipynb @@ -0,0 +1,158 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "079741c2", + "metadata": {}, + "source": [ + "# Grafische Benutzeroberflächen\n", + "\n", + "Es gibt wahnsinnig viele Toolkits, um grafische Anwendungen zu programmieren (z.B. GTK+ und Tk). Wir haben uns für [Qt](https://www.qt.io/) (in der Version 5) entschieden, weil die API nachvollziehbar ist und es auf sehr vielen Plattformen verfügbar ist.\n", + "\n", + "Für eine Anbindung an Python nehmen wir [PySide 2](https://wiki.qt.io/PySide2).\n", + "Dies ist leider in vielen Distributionen noch nicht in den Paketquellen enthalten.\n", + "Für die aktuelle Ubuntu LTS (16.04) muss z.B. das [PPA](https://launchpad.net/~thopiekar/+archive/ubuntu/pyside-git) `ppa:thopiekar/pyside-git` hinzugefügt und\n", + "das Paket `python3-pyside2` installiert werden.\n", + "\n", + "## Benötigte Module laden:\n", + "\n", + "Qt besteht aus vielen einzelnen Modulen - je nach Verwendung müssen die benötigten Module zuerst geladen werden.\n", + "Dies können (je nach Einsatz) mehr oder weniger sein - diese hier sind allerdings üblich:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "b47eaae5", + "metadata": {}, + "outputs": [], + "source": [ + "from PySide2.QtCore import *\n", + "from PySide2.QtGui import *\n", + "from PySide2.QtWidgets import *" + ] + }, + { + "cell_type": "markdown", + "id": "4288f6b5", + "metadata": {}, + "source": [ + "Für den nächsten Schritt benötigen wir zusätzlich noch das Python-Modul `sys`:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "266038f5", + "metadata": {}, + "outputs": [], + "source": [ + "import sys" + ] + }, + { + "cell_type": "markdown", + "id": "dd90e098", + "metadata": {}, + "source": [ + "## `QApplication`-Objekt erstellen\n", + "\n", + "Um überhaupt irgendetwas mit Qt machen zu können, brauchen wir eine Instanz von `QApplication`. (Bei reinen Konsolen-Anwendungen kann man auch `QCoreApplication` verwenden.)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "909d55ca", + "metadata": {}, + "outputs": [], + "source": [ + "app = QApplication(sys.argv)" + ] + }, + { + "cell_type": "markdown", + "id": "927b6ad8", + "metadata": {}, + "source": [ + "Die Befehlszeilenparameter unseres Programms geben wir an Qt weiter, damit es auf bestimmte Parameter darin reagieren kann (u.a. [diese](https://doc.qt.io/qt-5/qapplication.html#QApplication)).\n", + "\n", + "## Ein Widget erstellen:\n", + "\n", + "Alle grafischen Komponenten in Qt sind `QWidgets`.\n", + "\n", + "Der einfachste Fall ist ein `QLabel` - das zeigt einfach einen beliebigen Text an." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c810142a", + "metadata": {}, + "outputs": [], + "source": [ + "label = QLabel(\"Dies ist ein Text.\")\n", + "label.show()" + ] + }, + { + "cell_type": "markdown", + "id": "e30727f8", + "metadata": {}, + "source": [ + "Normalerweise würde man dieses Label in einem Fenster mit anderen Elementen unterbringen - in diesem einfachen Fall lassen wir das aber.\n", + "\n", + "## Die main loop:\n", + "\n", + "Jetzt ist alles so eingerichtet, wie wir das wollen.\n", + "Wir sehen aber noch nichts.\n", + "Wieso?\n", + "\n", + "Der wichtigste Teil fehlt noch:\n", + "Wir übergeben die Kontrolle des Programmablaufs an Qt:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "ba9639bb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "app.exec_()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Level_10/gravatar/fallback.jpg b/Level_10/gravatar/fallback.jpg new file mode 100644 index 0000000..0356f91 Binary files /dev/null and b/Level_10/gravatar/fallback.jpg differ diff --git a/Level_10/gravatar/gravatar.py b/Level_10/gravatar/gravatar.py new file mode 100644 index 0000000..b6e0ca0 --- /dev/null +++ b/Level_10/gravatar/gravatar.py @@ -0,0 +1,26 @@ +from hashlib import md5 +from base64 import b64encode +from pathlib import Path +import requests + +def get(email): + try: + return {"status": "ok", "url": get_image(email)} + except Exception as exc: + return {"status": "error", "error": str(exc)} + +def get_image(email): + print(f"get_image({email})") + if "@" not in email: + raise ValueError("E-Mail-Adresse ist ungültig.") + mail_hash = md5(email.strip().encode()).hexdigest() + url = "https://www.gravatar.com/avatar/" + mail_hash + # return url + try: + image = requests.get(url).content + except requests.exceptions.ConnectionError as exc: + image = Path("fallback.jpg").read_bytes() + # raise + # QML erwartet eine URL - wir haben aber das Bild als Bytes. + # data-URIs lösen das Problem. + return "data:image/jpeg;base64," + b64encode(image).decode() diff --git a/Level_10/gravatar/gravatar.qml b/Level_10/gravatar/gravatar.qml new file mode 100644 index 0000000..2a2d8a1 --- /dev/null +++ b/Level_10/gravatar/gravatar.qml @@ -0,0 +1,61 @@ +import QtQuick 2.5 +import QtQuick.Window 2.2 +import QtQuick.Layouts 1.3 +import QtQuick.Controls 1.4 +import io.thp.pyotherside 1.4 + +Window { + id: window + width: 360 + height: 360 + title: "Gravatar" + + ColumnLayout { + spacing: 2 + anchors.fill: parent + + Image { + id: avatar + source: "" + fillMode: Image.PreserveAspectFit + Layout.fillHeight: true + Layout.fillWidth: true + } + Label { + id: error_label + Layout.fillWidth: true + } + TextField { + id: mailinput + width: parent.width + text: "mail@example.com" + Layout.fillWidth: true + onEditingFinished: + { + py.call("gravatar.get", [mailinput.text], function(result) { + if(result["status"] == "ok") { + avatar.source = result["url"]; + error_label.text = ""; + } else { + avatar.source = ""; + error_label.text = result["error"]; + } + }); + } + } + } + Python { + id: py + Component.onCompleted: + { + // Add the directory of this .qml file to the search path + addImportPath(Qt.resolvedUrl('.')); + // Import the main module and load the data + importModule('gravatar', null); + } + onError: + { + error_label.text = traceback; + } + } +} diff --git a/Level_09/label.py b/Level_10/label.py similarity index 99% rename from Level_09/label.py rename to Level_10/label.py index fc6733a..d61ab02 100755 --- a/Level_09/label.py +++ b/Level_10/label.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# coding: utf-8 # Level 9: Ein Label in einem Fenster. diff --git a/Level_09/textbox.py b/Level_10/textbox.py similarity index 91% rename from Level_09/textbox.py rename to Level_10/textbox.py index 5668a9a..a6ee1b6 100755 --- a/Level_09/textbox.py +++ b/Level_10/textbox.py @@ -41,13 +41,13 @@ # die Funktion, die beim Klick ausgeführt werden soll -def onClick(): +def onClick() -> None: # die Eingabe holen input = text.text() - print("Eingabe: {}".format(input)) + print(f"Eingabe: {input}") # MessageBox erstellen mb = QMessageBox(QMessageBox.Information, "Titel", - "Der eingegebene Text war: \n{}".format(input), QMessageBox.Ok, window) + f"Der eingegebene Text war: \n{input}", QMessageBox.Ok, window) # MessageBox anzeigen mb.show() @@ -57,7 +57,7 @@ def onClick(): # Alternative: #button.clicked.connect(lambda: QMessageBox(QMessageBox.Information, "Titel", "Der eingegebene Text war: \n{}".format(text.text()), QMessageBox.Ok, window).show()) -# Fenster anzeigenw +# Fenster anzeigen window.show() # main loop diff --git a/Level_11/README b/Level_12/README similarity index 100% rename from Level_11/README rename to Level_12/README diff --git a/Level_11/pythonfoo_hello_world/__init__.py b/Level_12/pythonfoo_hello_world/__init__.py similarity index 82% rename from Level_11/pythonfoo_hello_world/__init__.py rename to Level_12/pythonfoo_hello_world/__init__.py index d28c7ed..fbf1362 100644 --- a/Level_11/pythonfoo_hello_world/__init__.py +++ b/Level_12/pythonfoo_hello_world/__init__.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -def run(): +def run() -> None: print("Hello World!") if __name__ == '__main__': diff --git a/Level_11/run.sh b/Level_12/run.sh similarity index 100% rename from Level_11/run.sh rename to Level_12/run.sh diff --git a/Level_11/setup.py b/Level_12/setup.py similarity index 96% rename from Level_11/setup.py rename to Level_12/setup.py index 4ea520c..3ce0495 100755 --- a/Level_11/setup.py +++ b/Level_12/setup.py @@ -42,14 +42,12 @@ # Indicate who your project is intended for 'Intended Audience :: Developers', - 'Intended Audience :: End Users/Desktop', # Language 'Natural Language :: English', # Topic 'Topic :: Utilities', - 'Topic :: Internet', # Specify the Python versions you support here. 'Programming Language :: Python :: 3', diff --git a/Notizen.md b/Notizen.md new file mode 100644 index 0000000..c409f27 --- /dev/null +++ b/Notizen.md @@ -0,0 +1,25 @@ +#Notizen: +## Ideen: +* Einstieg in Funktionen mit `turtle` +* Gliederung in Ordner pro Level +* Aufteilung in Präsentationsdateien und Code Beispiele +* genauere Formulierung der Aufgaben pro Level im Wiki +* Verlinkung der Seiten im Wiki mit den Codebeispielen +* Decoratoren: Als Beispiel das Cachen von Werten bei rekursiven mathematischen Funktionen +* Dokumentation: Sphinx + +## ToDo: +* anspruchsvollere Aufgaben +* Weitere .md Dateien zu jedem Level im Wiki +* Codebeispiele zu jedem Level im Repository +* Lösungen für die Aufgaben +* Glossar vervollständigen +* ~~Kapitel 4~~ +* Link zu Operatoren.md, wenn es um .append geht, in Kapitel 3 +* Kapitel 2: Soll hier eine Verknüpfung zur PW Datei / Erklärung entstehen? +* Erklärung Vorteile / Anwendungsmöglichkeiten der Schleifen +* `with` in Level 7 +* Kapitel zu CLI-Anwendungen (argparse usw.) +* Sets und listcomprehensions +* with in Level 7 +* pip erwähnen \ No newline at end of file diff --git a/Operatoren.md b/Operatoren.md new file mode 100644 index 0000000..705f53d --- /dev/null +++ b/Operatoren.md @@ -0,0 +1,58 @@ +# Operatoren + +Python kennt diverse Operatoren (z.B. `+`, `-`, `*` und `/`). +Diese sind allerdings nicht in der Sprache festgelegt, +sondern sie hängen von den verwendeten Datentypen ab und werden dort definiert. +Es ist sogar möglich (und erwünscht!), sie mit eigenen Datentypen zu verwenden. + +## int + +Auf `int`-Werte angewandt, verhalten sich die Operatoren wie normale Rechenoperatoren. + + * ` + -> `: Die Summe der beiden Zahlen. + * ` - -> `: Die Differenz der beiden Zahlen. + * ` * -> `: Das Produkt der beiden Zahlen. + * ` / -> `: Der (exakte) Quotient der beiden Zahlen. + * ` // -> `: Der abgerundete Quotient der beiden Zahlen. + * ` % -> `: Modulo Division (Rest einer Division) + * ` ** -> `: Die Potenz der beiden Zahlen. + * ` << -> `: Bitshift nach links (äquivalent zu ` * (2 ** )`) + * ` >> -> `: Bitshift nach rechts (äquivalent zu ` // (2 ** )`) + * ` ^ -> `: bitweises XOR + +## float + +Bei `float`-Werten funktioniert das fast alles genau so wie bei `int` mit der Besonderheit, +dass alle Rückgabewerte auch `float` sind. (Dies gilt auch, wenn `int` und `float` gemischt werden.) +Außerdem funktionieren die Bitoperatoren `<<`, `>>` und `^` nicht auf floats. + +## bool + +Die oben beschriebenen `int`-Operationen lassen sich auch auf `bool`-Werte anwenden. Dabei gilt: + + * `True == 1` + * `False == 0` + +Außerdem gibt es auch noch weitere boolesche Operatoren: + + * ` and -> `: logisches Und + * ` or -> `: logisches Oder + * `not -> `: logisches Nicht + +## str + +Bei Strings ist das Verhalten auch sinnvoll, aber auf den ersten Blick eventuell anders als erwartet: + + * ` + -> `: Verkettet die beiden Strings. + * ` * -> `: Hängt den String n-mal hintereinander. (äquivalent zu n-mal `+`) + +## list + +Bei Listen funktioniert das auch: + + * ` + -> `: Verkettet die beiden Listen. + * ` * -> `: Hängt die Liste n-mal hintereinander. (äquivalent zu n-mal `+`) + +## tuple + +Bei Tupeln funktioniert alles genau wie bei Listen mit der Besonderheit, dass alle Rückgabewerte auch `tuple` sind. diff --git a/Python27.md b/Python27.md new file mode 100644 index 0000000..543a36b --- /dev/null +++ b/Python27.md @@ -0,0 +1,41 @@ +# Python 2.7 + +Wir stellen nur aktuelle Versionen von Python vor. +Es kann allerdings sein, dass man für manche (sehr speziellen) Einsatzzwecke Python 2.7 verwenden muss. + +Mit dem Erscheinen von Python 3.0 wurden einige größere Änderungen eingebracht - und die fehlen dann natürlich in 2.7. Außerdem hat die Standardbibliothek im Laufe der Zeit einige neue Module erhalten. + +## Aktivieren des bereits unterstützten neuen Verhaltens + +Python 2.7 unterstützt viele Änderungen in Python 3.0 schon - sie müssen nur noch aktiviert werden. Dazu müssen die folgenden zwei Zeilen an den Anfang (!) jeder Datei gepackt werden: + + +```python +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function, unicode_literals +from io import open +``` + +(Warum unbedingt an den Anfang der Datei? +Syntaktisch ist das ein Kommentar und ein `import`-Statement, semantisch sind dies allerdings Anweisungen an den Compiler.) + +Die erste Zeile sorgt dafür, dass der Quellcode als [UTF-8](http://utf8everywhere.org/) gelesen wird. +Die zweite Zeile aktiviert die neue Import-Reihenfolge, die neue Division (`/` gibt `float` zurück), die `print`-Funktion (statt einem Statement) und Unicode-Strings als Standard. +Die dritte Zeile ersetzt `open` durch das aus Python 3 bekannte. + +## Dinge, die anders sind + + * `input` heißt `raw_input` + * viele Funktionen geben Listen oder Tupel zurück statt Iteratoren (z.B. `xrange` statt `range` verwenden) + * viele Funktionen verwenden Bytestrings statt Unicodestrings + * Klassen müssen explizit von `object` erben + * `int`s, `list`s und `dict`s haben eine maximale Länge (eventuell statt `int` `long` verwenden) + * einige Dinge in der Standardbibliothek wurden verschoben (siehe z.B. [diese Tabelle](https://six.readthedocs.io/#module-six.moves)) + * ... + + +## neue Module aus der Standardbibliothek, die sich nachinstallieren lassen + + * [ipaddress](https://pypi.org/project/ipaddress/) + * [enum34](https://pypi.org/project/enum34/) + * ... diff --git a/README.md b/README.md index 832221d..7e62b1c 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,188 @@ **tl, dr** The repository for PythonfooLite. The meeting for beginners in Python. -Siehe auch unser [Wiki](https://github.com/pythonfoo/pythonfooLite/wiki). +Und in ausführlich: +Dies ist das Repository für das PythonfooLite, dem Meeting für Anfänger in der Programmiersprache Python. Es enthält sowohl Codebeispiele als auch Hilfstexte. Diese sollen dabei helfen, einen Einstieg in Python zu bekommen. Dabei sind die Codebeispiele in Level unterteilt, zum einem aus Gründen der Übersichtlichkeit und andererseits damit jemand, der schon einmal programmiert hat die Anfänge überspringen kann. Wenn du Python lernen möchtest, komm doch mal am ersten oder zweiten Donnerstag im Monat im Chaosdorf vorbei. Du kannst natürlich auch gerne zu Hause die Codebeispiele durchgehen. -### Und in ausführlich: -Dies ist das Repository für das PythonfooLite, dem Meeting für Anfänger in der Programmiersprache Python. Es enthält sowohl Codebeispiele als auch Hilfstexte. Diese sollen dabei helfen, einen Einstieg in Python zu bekommen. Dabei sind die Codebeispiele in Level unterteilt, zum einem aus Gründen der Übersichtlichkeit und andererseits damit jemand, der schon einmal programmiert hat die Anfänge überspringen kann. Wenn du Python lernen möchtest, komm doch mal am ersten oder zweiten Donnerstag im Monat im Chaosdorf vorbei. Du kannst natürlich auch gerne zu Hause die Codebeispiele durchgehen. \ No newline at end of file +## Einleitung + +> "The only way to learn a new programming language is by writing programs in it." - Dennis Ritchie + +Das PythonfooLite beschäftigt sich dezidiert mit Programmieranfängern oder Python-Neulingen. Aus der Erfahrung heraus, das diese im sich "normalen" Pythonfoo abgehängt fühlen, widmen wir die ersten beiden Donnerstage jedes Monats den Neulingen. Wer Lust hat kommt einfach vorbei, jeweils am ersten oder zweiten Donnerstag im Monat ab 18:00 im Chaosdorf. Es hilft einen tragbaren Rechner mitzubringen, auf dem man auch Programme installieren kann. Vorwissen über Programmierung wird nicht benötigt. + +## Python +Wir beschäftigen uns beim Pythonfoo mit Python in der Version 3.x. Python ist eine Programmiersprache, die leicht zu lernen aber schwer zu meistern ist ("easy to learn, hard to master"). Das soll uns aber nicht abschrecken. Python verzichtet auf einige Eigenheiten populärer Sprachen (wie z.B. Java oder C), büßt somit Performanz ein, ist allerdings leichter zu lernen. Wenn man sich lange genug mit Python beschäftigt, ist es problemlos möglich andere Programmiersprachen zu lernen, da Grundlegende Konzepte schon aus der Theorie und Praxis bekannt sind und auf diesen aufgebaut werden kann. + +## Sprache +Grundsätzlich sind alle Texte in Deutsch verfasst, die Codebeispiele jedoch enthalten teilweise englische Namen, da auch die Programmiersprache mit englischen Begriffen arbeitet. An einigen Stellen, werden in den Texten englische Begriffe verwendet, was meistens daran liegt, dass die deutsche Übersetzung sehr sperrig ist ("integer" <-> "ganze Zahl", "float" <-> "Fließkommazahl") oder weil der englische Begriff der weitaus gebräuchlichere ist. + +## Glossar +Im Wiki des Github Repositories findest du ein Glossar, in dem die meisten Begriffe kurz erklärt werden. + +## Kontakt und Feedback +Falls du Anregungen, Fragen, Einwände oder Ideen hast, kannst du uns natürlich an den ersten beiden Donnerstagen im Monat im Chaosdorf erreichen, oder eine Nachricht im Github Repository hinterlassen oder eine E-Mail an [pythonfoo@chaosdorf.de](mailto:pythonfoo@chaosdorf.de) schicken, zudem bietet GitHub noch ein Issue System, um Fehler im Repository zu melden. Wir sind über jegliche Art von Feedback dankbar. +Da wir nur zwei Studenten sind, die Spaß daran haben, anderen die Grundlagen der Programmierung in Python näher zu bringen, sind wir natürlich weder allwissend oder unfehlbar. Die Codebeispiele und das Wiki im Repository sind insofern als "work in progress" zu sehen, dennoch sind wir für jegliches Feedback dankbar. Wir sind stetig damit beschäftigt die Codebeispiele und beiliegenden Texte zu erweitern und verbessern, auch in diesem Zusammenhang freuen wir uns über jegliches Feedback. + +## Gliederung +Wir haben den Ablauf in Level unterteilt, die aufeinander aufbauen. Das sorgt dafür, dass wir den Ablauf individuell an den Kenntnisstand der Anwesenden anpassen können, was es nicht langweilig werden lässt. Die Level sind unten grob skizziert und geben einen Überblick. Zu jedem Level sind Stichwörter aufgeführt, die sich entweder im Glossar oder im Internet suchen lassen, und einen Einblick geben sollen um was es geht, damit du falls du bereits Erfahrung im Programmieren mit Python oder einer anderen Programmiersprache hast, weißt wo du am besten einsteigen kannst. + +### Zeiteinteilung +Da die Level nicht gleich umfangreich sind und die Geschwindigkeit des Durchgehens stark vom Kenntnisstand bzw. eventuellen Vorkenntnissen abhängig ist, ist es schwierig allgemein zu sagen, wie viel Zeit für die Level eingeplant werden muss; die Erfahrung zeigt aber, dass die ersten 5 Level gut in einen bis zwei Abenden à 3 Stunden beendet werden können. Da zwischen Level 5.5 und Level 6 ein großer inhaltlicher Sprung besteht, bietet es sich an zwischen den Levels eine Pause zur Auffrischung und Wiederholung einzulegen. Zudem ist der Einstieg in Level 6 zuerst theoretisch, weshalb es besser ist, ausgeruht in das Level zu starten. + +### Aufgaben +Zur Auffrischung und Anwendung des Gelernten, bieten wir zu den meisten Level Aufgaben an, die sich auf das Level beziehen und der Übung dienen sollen. Die Aufgaben sind natürlich vollkommen freiwillig wir schauen gerne über Lösungen drüber. In einigen Levels gibt es auch Beispiellösungen zu den Aufgaben. Da es für uns schwierig ist den Schwierigkeitsgrad der Aufgaben richtig zu wählen, sind wir hier auf Feedback angewiesen. + +### Level 0 +Level 0 ist Programmieranfänger gedacht und klärt die Grundlagen von Programmierung im Allgemeinen und mit Python. +#### Stichwörter: +* Programmiersprache +* Anweisung +* Compiler +* Interpreter +* hello_world.py +* Code + +### Level 1 +Level 1 beginnt mit dem Programmieren einfacher Programme in Python und klärt Grundlegende Konzepte der Programmierung in Python, die sich aber auch auf andere Programmiersprachen übertragen lassen. +#### Stichwörter: +* Variable +* Typ +* Wert +* Ausdruck +* Integer +* Float +* String +* Eingabe +* Ausgabe +* Schlüsselwort +* Kommentar + +### Level 2 +Level 2 führt eine erste Kontrollstruktur ein, welche ein wichtiges Element jeder Programmiersprache darstellt. Des Weiteren wird ein neuer Typ eingeführt. +#### Stichwörter: +* Programmablauf +* if-Bedingung +* while-Schleife +* Boolean + +### Level 3 +Level 3 beschäftigt sich nun mit einer weiteren Kommandostruktur, den Schleifen und führt dazu drei neue Typen ein. Nach Abschluss von Level 3, kann in der Theorie jedes Programm schon geschrieben werden. +#### Stichwörter: +* for-Schleife +* Liste +* Tupel +* Dictionary +* Sets + +### Level 4 +Level 4 beschäftigt sich mit dem Lesen und Bearbeiten von Textdateien. +#### Stichwörter: +* `pathlib` +* `shutil` +* Dateien lesen +* Dateien speichern +* Dateien verschieben +* Dateien löschen + +### Level 5 +Level 5 beschäftigt sich mit dem Erstellen von Funktionen (ob mit oder ohne Parameter / Übergabewert) und Rekursion. +#### Stichwörter: +* Funktion +* Gültigkeitsbereich +* Rekursion +* Rückgabewert +* Docstrings + +### Level 5.5 +Dieses Level beschäftigt sich mit Themen, die in bisherigen Level nicht behandelt wurden, weil sie nichts mit Python zu tun haben oder nicht dem Fortschritt entsprachen. Dennoch sind diese Themen, nicht nur für die Programmierung in Python, sondern auch in anderen Programmiersprachen, sehr wichtig. + +#### Stichwörter: +* Texteditor +* IDE +* Git und GitHub +* [PEP8](https://www.python.org/dev/peps/pep-0008/) +* `s.format()` +* Bash / Terminal / Shell +* JSON / CSV / TOML +* Fehlersuche +* Refactoring + +### Level 6 + +In Level 6 geht es um Konsolen-Anwendungen. Diese kann man grob in zwei Arten unterteilen: + * Programme, die nur Parameter entgegennehmen und etwas ausgeben + * Programme, die interaktiv arbeiten + +Einfache Formen des letzteren Typs kamen bereits in den vorigen Level vor. + +#### Stichwörter: + * `argparse` + * `curses` + +### Level 7 (OOP 1) +Level 7 widmet sich dem Bereich der Objektorientierten Programmierung. Dieses Konzept hat auch in vielen anderen Programmiersprachen eine große Bedeutung. In diesen Level werden die Kompetenzen vermittelt um eigene Typen zu definieren, Klassen oder Module zu schreiben, sowie ein grundsätzliches Verständnis von Objektorientierter Programmierung. + +#### Stichwörter: +* Klassen +* Bibliotheken +* Objekt +* Module +* Imports +* Attribute und Methoden +* Vererbung +* Überladung +* `super()` +* `isInstance()` und `is` + +### Level 8 +Level 8 beschäftigt sich mit Dingen, die thematisch in andere Level gehören, aber nicht zu deren Kenntnisstand passen. + +#### Exkurse: +* `turtle` - Ein Modul zum Steuern einer Schildkröte +* `random` - Ein Modul dass verschiedene Methoden für Pseudozufallszahlen bereitstellt +#### Stichwörter: +* Generatoren +* Decoratoren +* Exceptions +* `map()` und `zip()` +* assert + +**Folgendes ist eher fortgeschritten.** + +### Level 9 Nebenläufigkeit und Alternativen +* Threads +* `multiprocessing` +* `asyncio` + +### Level 10 GUI +Es gibt wahnsinnig viele Möglichkeiten, +grafische Benutzeroberflächen mit Python zu realisieren. +Wir beschränken uns hier auf Qt 5 als GUI-Toolkit. +**nur kurz anreißen!** + +#### Aufgaben +Ein Hauptfenster soll einen Button und ein Textfeld +enthalten. Beim Klick auf den Button soll der Inhalt des +Textfelds in einem Dialog angezeigt werden. + +### Level 11 Web +Webanwendungen sind ein häufiger Einsatzzweck von Python. +* Was ist HTTP und wie funktioniert es? +* [requests](http://docs.python-requests.org/en/latest/) +* [BeautifulSoup](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) +* CGI +* WSGI +* [Werkzeug](http://werkzeug.pocoo.org/) +* [Django](https://www.djangoproject.com/) (/[Flask](http://flask.pocoo.org/)?) **nur kurz anreißen!** + +#### Aufgaben +* *Hallo Welt!* als Webapp + +### Level 12 Packaging und Repos +Mit `setuptools` und `pip` kann man Pakete erstellen, packen und installieren. +* [pypi](https://pypi.org/) als Repository +* Pakete aus dem Internet herunterladen und installieren +* Pakete erstellen +* Pakete bauen +* Pakete hochladen diff --git a/Rekursion_Vs._Iteration.md b/Rekursion_Vs._Iteration.md new file mode 100644 index 0000000..8b7023d --- /dev/null +++ b/Rekursion_Vs._Iteration.md @@ -0,0 +1,65 @@ +# Rekursion Vs. Iteration +## Einleitung +Zum Anfang betrachten wir, was genau Rekursion ist. Im Grunde ist Rekursion nämlich nur ein Sprachfeature, dass eine Funktion sich selber aufrufen kann. Jedoch ist eine Programmiersprache auch ohne Rekursion Turing komplett, d.h. ich kann jedes Programm auch ohne Rekursion implementieren. Das wird unter anderem dadurch deutlich, dass eine rekursive Funktion beim Übersetzen in Maschinencode als Schleife ausgeführt wird. Zusammenfassend kann man also sagen: + +> Alles was sich iterativ implementieren lässt, lässt sich auch rekursiv +> implementieren und anders herum. + +Rekursion bietet sich an, da viele Algorithmen rekursiv definiert sind und daher rekursiv leichter zu implementieren sind als iterativ. Damit ist jedoch nicht gesagt, dass die rekursive Implementierung die effizientere ist. Ein einfaches Beispiel dafür sind die Fibonacci-Zahlen. + +## Die Fibonacci-Zahlen +Die Fibonacci-Zahlen tauchen in der Natur auf und sind eine relativ schnell wachsende Zahlenfolge, die folgendermaßen definiert ist: +``` +fib(0) = 1 +fib(1) = 1 +fib(n) = fib(n-2) + fib(n-1) +``` +### Einfache rekursive Implementierung + +Die Definition ist eindeutig rekursiv, folglich wäre der simpelste Ansatz diese Zahlenfolge zu implementieren die folgende: +``` python +def fibR(n): # Fibonacci Rekursiv + if n == 0 or n == 1: + return 1 + return fibR(n-2) + fibR(n-1) +``` + +### Probleme + +Dieser Code funktioniert, ist leicht zu lesen hat aber einige Nachteile: + +#### Rekursionslimit + +Der Rekursion ist ein Limit gesetzt, weshalb der Code bei größeren Zahlen in einen `RecursionError`laufen wird. In diesem Fall passiert dies schon sehr früh, weil es zwei rekursive Aufrufe in der Funktion gibt. + +#### Laufzeit + +Das weitaus größere Problem ist die Laufzeit, denn dadurch, dass fibR(n-2) und fibR(n-1) aufgerufen werden, wird fibR() immer häufiger aufgerufen: +``` +n = 5 +fibR(5) wird 1 mal aufgerufen +fibR(4) wird 1 aufgerufen +fibR(3) wird 2 mal aufgerufen +fibR(2) wird 3 mal aufgerufen +fibR(1) wird 5 mal aufgerufen +fibR(0) wird 8 mal aufgerufen +``` +Wenn man sich die Anzahl der Aufrufe genau anschaut, stellt man fest dass es sich um die Fibonaccifolge handelt. Die rekursive Implementation berechnet also ihre eigene Laufzeit. Da die Fibonaccifolge aber relativ schnell wächst, wächst auch die Laufzeit relativ schnell. + +### Lösung + +Da jeder Algorithmus sowohl rekursiv, als auch iterativ implementiert werden kann und die rekursive Implementation Probleme aufwies, versuchen wir jetzt die Fibonacci Folge iterativ zu implementieren: + +``` +def fibI(n): # Fibonacci Iterativ + last = 1 + current = 1 + for i in range(0,n): + current, last = current + last, current + return current +``` + +Diese Funktion implementiert die Folge iterativ, läuft daher nicht in einen `RecursionError` benötigt `n` Durchläufe der Schleife, ist also deutlich schneller als die rekursive Implementierung. + +### Fazit +Die beiden gezeigten Implementierungen eines einfachen Problems, waren ungefähr gleich komplex, haben sich aber in der Laufzeit stark unterschieden. Beide Möglichkeiten der Implementation haben jedoch ihre Vorzüge, weshalb im Einzelfall entschieden werden muss, mit welcher Methode ein Algorithmus implementiert wird. diff --git a/Shell.md b/Shell.md new file mode 100644 index 0000000..2e30c45 --- /dev/null +++ b/Shell.md @@ -0,0 +1,27 @@ +# Der Umgang mit der Shell +***ToDo:** Hier den Link zum Kurs von Github für Git* +## Was ist die Shell? +## Wie rufe ich die Shell auf? +In UNIX Systemen wird meistens als Terminal oder Konsole ein Shell Emulator geöffnet. +Diese können eine Graphische Oberfläche haben, können aber auch nur Textbasiert sein (beispielsweise die Standard Terminals tty1 - tty6). +## Welche Unterschiede gibt es zwischen den Betriebssystemen? +## Welche Befehle sind für den Anfang wichtig? +#### UNIX: +* **cd** - Wechselt das Verzeichnis in den angegebenen Pfad +* **mv** - Verschiebt eine Datei oder einen Ordner +* **touch** - Legt eine leere Datei an +* **mkdir** - Legt ein neues Verzeichnis an +* **ls** - Listet den Inhalt eines Verzeichnisses auf +* **rm** - Löscht eine Datei oder ein Verzeichnis +* **man** - Öffnet den Handbucheintrag zu einem Befehl oder Programm +* **clear** - Löscht die aktuelle Ausgabe +#### Windows: + + +## Welche Konsolen-Programme empfehlt ihr mir? + +* **htop** - Prozessmonitor in der Konsole in Farbe (UNIX Systeme) +* **git** - Ein Konsolen-Programm zur Versionskontrolle (siehe "Versionskontrolle.md") +* **pip3** - Paketmanager für Python3 Bibliotheken (UNIX Systeme) +* **bpython3** - Bunter Python-Interpreter mit Autovervollständigung (UNIX Systeme) +* **fish** - Weitere Shell mit Features, Unterschiede zur **Bash** vorhanden (UNIX Systeme) \ No newline at end of file diff --git a/Versionskontrolle.md b/Versionskontrolle.md new file mode 100644 index 0000000..0aaa58e --- /dev/null +++ b/Versionskontrolle.md @@ -0,0 +1,27 @@ +# Einstieg in Git und Github +## Was ist Versionskontrolle? +Mit einer Versionskontrolle ist es möglich die verschiedenen Versionen eines Programms, welche beim Programmieren natürlich entstehen, zu dokumentieren. So ist es möglich Änderungen rückgängig zu machen verschiedene Entwicklungszweige zusammen zu führen oder die Arbeit mehrerer Leute mit einander zu verknüpfen. + +## Warum möchte ich Versionskontrolle haben? +Mit einer funktionierenden Versionskontrolle kann ich: + + * Mit vielen Leuten an einem Projekt arbeiten, ohne sich im Weg zu stehen + * Schnell die Version finden, bei der alles kaputt ging + * Auf einfache Weise nachvollziehen wie sich mein Projekt entwickelt hat + * Den Fortschritt meines Projektes im Auge behalten + +Versionsverwaltung hat zwar nur indirekt mit Programmierung zu tun, ist aber ein sehr praktisches Hilfsmittel, gerade wenn es um größere Projekte geht, an denen eventuell auch mehrere Leute arbeiten. Durch die Möglichkeit zu einer bestimmten Version zurückspringen zu können, wird es einfacher Fehler zu finden. Sobald die Verwaltung der Versionskontrolle in den Workflow eines Projektes übergegangen ist, wird die Entwicklung + +## Was ist git? +Nachdem jetzt (hoffentlich) klar wurde, warum Versionskontrolle beim Programmieren eine gute Idee ist, ist es natürlich wichtig zu wissen, wie man das denn umsetzt, dazu gibt es glücklicherweise eine einfache Möglichkeit: Git. Git ist, sehr vereinfacht, eine Möglichkeit Versionskontrolle durchzuführen, die sich bewährt hat. + +## Wie funktioniert Git? + +## Wie benutze ich git? +Git lässt sich unter UNIX als Konsolen-Programm ausführen, unter Windows ist das EInbinden und das Arbeiten mit Git etwas komplexer. + +### Ich will aber nicht in der Konsole arbeiten +Es gibt sowohl unter Windows als auch unter Linux, Programme mit einer graphischen Oberfläche, welche git dann im Hintergrund aufrufen, falls einem die Arbeit mit der Konsole zu kompliziert erscheint. Allerdings lassen sich gerade die komplexeren Operationen in der Konsole komfortabler lösen lassen und die Hilfestellungen im Internet™ häufig zu den Konsolen-Befehlen ausführlicher sind. + +## Was ist Github? +## Wie benutze ich Github? diff --git a/passwort.md b/passwort.md new file mode 100644 index 0000000..79a77b9 --- /dev/null +++ b/passwort.md @@ -0,0 +1,138 @@ +# Einfache Passwortabfragen +Passwortabfragen werden häufig benutzt um die Authentizität eines Nutzers zu überprüfen, dabei bildet ein Passwort eine Art Geheimnis, dass ich dem Dienst mitgeteilt habe und das, im Idealfall, nur mir bekannt sein sollte. Somit kann ich dem Dienst zumindest zeigen, dass ich die Person hinter diesem Account bin. In Zeiten von Zwei-Faktor Authentifizierung geraten einfache Passwortabfragen immer mehr in den Hintergrund, sie dienen hier aber auch nur als anschauliches Beispiel zum Umgang mit if-Bedingungen und generell zur Art, wie man ein Programm schreibt. +Generell sollten wir beim Programmieren immer darauf achten, möglichst einfach anzufangen, dabei erkennt man dann wie der Code noch verbessert werden kann. Wir schreiben also ersteinmal Code, der auf die simpelste Art und Weise den Anforderungen entspricht und verbessern ihn fortlaufend. Dabei kann uns auch Versionskontrolle helfen Änderungen zu widerrufen. +Wenn wir also als Anforderung hätten +**Schreiben SIe ein Programm, das ein Passwort abfragt und etwas ausgibt, falls das Passwort dem vorgegebenen entspricht.** +würde folgendes Programm der Anforderungen komplett entsprechen: + +```python +password = "12345678" +password_input = input("Bitte geben Sie das Passwort ein: ") +if password == password_input: + print("Zugang gewährt") +``` + +Theoretisch könnte man selbst dieses Programm weiter vereinfachen, worauf wir an der Stelle aber verzichten. +Es dürften aber schon einige Schwachstellen aufgefallen sein: + +* Es gibt keine Ausgabe bei Eingabe eines falschen Passworts +* Das Programm beendet direkt nach einer falschen Eingabe +* Der Benutzer hat nur eine Möglichkeit das Passwort einzugeben +* Das Passwort kann beim Eingeben gelesen werden +* Das Passwort kann aus dem Quellcode gelesen werden + +Um diese Nachteile wollen wir uns jetzt kleinschrittig kümmern, um am Ende ein Programm geschrieben zu haben, dass die selben Anforderungen vom Anfang erfüllt aber noch zusätzlich die Nachteile ausbügelt. +### Es gibt keine Ausgabe bei Eingabe eines falschen Passwort +Dies lässt sich mit wenig Aufwand am vorhandenen Code ändern: + +```python +password = "12345678" +password_input = input("Bitte geben Sie das Passwort ein: ") +if password == password_input: + print("Zugang gewährt") +else: + print("Das Passwort war falsch") +``` +Durch den `else`-Zweig wird auch etwas ausgegeben, falls das Passwort nicht richtig war. + +### Das Programm beendet direkt nach einer falschen Eingabe +Hier bemerken wir, dass wir ihn schon behoben haben, da jetzt etwas ausgegeben wird. +###Der Benutzer hat nur eine Möglichkeit das Passwort einzugeben +Dies ist tatsächlich ein Problem, da gerade bei langen komplizierten Passwörtern die Möglichkeit größer wird, sich bei einem einzigen Zeichen zu vertun. Wir wollen also nun dem Benutzer 3 Versuche geben das Passwort richtig einzugeben: +```python +password = "12345678" +counter = 1 +while counter <= 3 + password_input = input("Bitte geben Sie das Passwort ein: ") + if password == password_input: + print("Zugang gewährt") + break + else: + print("Das Passwort war falsch") + counter += 1 +``` +Durch das benutzen der while-Schleife hat der Benutzer jetzt 3 Versuche das Passwort einzugeben, ohne, dass es neu abgefragt wird, wenn es bereits richtig eingegeben wurde. Hier wurde ein Teil der Optimierung schon implizit übernommen, da eine Schleife nicht notwendig gewesen wäre um ein Password 3 mal abzufragen. So hätte man das Programm auch folgendermaßen schreiben können: +```python +password = "12345678" +access = False +if not access: + password_input = input("Bitte geben Sie das Passwort ein: ") + if password == password_input: + print("Zugang gewährt") + access = True + else: + print("Das Passwort war falsch") + +if not access: + password_input = input("Bitte geben Sie das Passwort ein: ") + if password == password_input: + print("Zugang gewährt") + access = True + else: + print("Das Passwort war falsch") + +if not access: + password_input = input("Bitte geben Sie das Passwort ein: ") + if password == password_input: + print("Zugang gewährt") + access = True + else: + print("Das Passwort war falsch") + +``` +Spätestens jetzt sollte aber aufgefallen sein, das eine Schleife hier angebracht ist, zumal manchmal das Passwort ja auch 10-mal eingegeben werden kann. + +### Das Passwort kann beim Eingeben gelesen werden +Um diesen Issue zu beheben müssen wir uns von der `input()` Funktion trennen, da bei ihrer Benutzung immer die Eingabe angezeigt wird. Daher benutzen wir nun die `getpass` Methode aus dem Modul `getpass`: +``` +from getpass import getpass as passinput +password = "12345678" +counter = 1 +while counter <= 3 + password_input = passinput("Bitte geben Sie das Passwort ein: ") + if password == password_input: + print("Zugang gewährt") + break + else: + print("Das Passwort war falsch") + counter += 1 +``` +Zum Glück funktioniert `getpass.getpass()`fast genauso wie `input()` weshalb wir nur minimale Änderungen vornehmen mussten. Was aber auffällt ist, das wir gerade etwas geändert haben, was seit der ersten Version des Programms schon da war und somit sehr relevant war. Das sollte uns daran erinnern, das wir kein Code in Stein meißeln sondern so agil sein müssen, auch altbewährtes neu zu schreiben. + +### Das Passwort kann aus dem Quellcode gelesen werden +Dieser Issue ist gewissermaßen ein wenig widersinnig, denn bisher kann das unser Programm vom Benutzer geändert werden. Trotzdem wollen wir uns anschauen wie dieser Issue geschlossen werden kann. Dafür müssen wir uns kurz mit Hashwerten befassen. Das Prinzip hinter einem Hashwert ist, dass ich aus einer Eingabe einen Wert erzeuge, wobei die Eingabe immer zu diesem Hashwert führen wird aber auch andere Eingaben zu diesem Hashwert führen können, weshalb man aus dem Hashwert nicht auf die Eingabe schließen kann. Beim Hashen der Eingabe gehen Informationen verloren, die nicht wiederhergestellt werden können. Genau diesen Effekt nutzen wir im Folgenden aus. + +```python +import bcrypt +pwd = b"Test1234" +salt = bcrypt.gensalt() +hashed_pwd = bcrypt.hashpw(pwd,salt) +print(hashed_pwd) +``` + +Doch wie nutzen wir den jetzt konkret Hashwerte für unsere Passwortabfrage? Nun im folgenden werden wir nicht mehr Passworteingabe und Passwort vergleichen, sondern die Passworteingabe hashen und mit dem Hash vom Passwort vergleichen, sodass das Passwort selber nicht im Quellcode steht. Wir nutzen dafür das `bcrypt` Modul, das für das Hashen von Passwörtern gedacht ist. +Nun können wir unser Programm umändern: + +``` python +from getpass import getpass as passinput +import bcrypt +passwordHash = "" +counter = 1 +while counter <= 3 + password_input = passinput("Bitte geben Sie das Passwort ein: ") + password_input = password_input.encode(password_input) + salt = bcrypt.gensalt() + inputHash = bcrypt.hashpw(password_input, salt) + if passwordHash == inputHash: + print("Zugang gewährt") + break + else: + print("Das Passwort war falsch") + counter += 1 +``` +Es liegt aber noch ein Problem vor: +Hash-Funktionen verlieren Informationen, das heißt, dass mehrere Eingaben den selben Hashwert liefern können, weshalb der Benutzer nicht **das** Passwort eingeben muss, dass den Hashwert ergibt, sondern nur **eins** von denen, die diesen Hashwert ergeben. An dieser Stelle vertrauen wir darauf, dass die Wahrscheinlichkeit für so eine Kollision niedrig genug ist um sie zu tolerieren, zumal wir ja die Eingabe auf 3 Versuche beschränkt haben.s + +## Fazit: +Wir haben mit einem Programm angefangen, das genau den gestellten Anforderungen entsprach. Anschließend haben wir Probleme mit unseren Programm ausgemacht und diese Issues in 5 Schritten behoben. Dabei haben wir zuerst nur Funktionalität hinzugefügt und in den letzten beiden Schritten auch bestehenden Code verändert. Wir haben aber die Funktionalität der ersten Version erhalten gelassen. Diesen Vorgang nennt man Refactoring. Bei dem Optimieren des Codes kann Versionskontrolle eine sehr wichtige Rolle spielen, denn es kann sein, dass man den Code über-optimiert und er auf ein mal nicht mehr tut was er soll. Vorausgesetzt man hat eine ordentliche Versionskontrolle durchgeführt, kann man nun von dem letzten funktionierenden Stand aus vorwärts gehen und so die Änderung ausfindig machen, die das Programm zerschossen hat. +Sowohl zu Refactoring als auch zu Versionskontrolle haben wir eigene Folien (geplant). diff --git a/random.md b/random.md new file mode 100644 index 0000000..8f10bdf --- /dev/null +++ b/random.md @@ -0,0 +1,53 @@ +# random +Das Modul random ermöglicht einfache aber vielfältige Operationen mit Zufallszahlen. Hierbei sei gesagt, dass der eingebaute Zufallsgenerator bei weitem nicht der Beste ist und schon gar nicht für kryptographische Operationen genutzt werden sollte. +Wir fangen damit an das Modul random zu importieren und uns die Attribute und Methoden anzuschauen: +```python +import random +print(dir(random)) +``` +Als Ausgabe bekommen wir: +```python +['BPF', 'LOG4', 'NV_MAGICCONST', 'RECIP_BPF', 'Random', 'SG_MAGICCONST', 'SystemRandom', 'TWOPI', '_BuiltinMethodType', '_MethodType', '_Sequence', '_Set', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_acos', '_ceil', '_cos', '_e', '_exp', '_inst', '_log', '_pi', '_random', '_sha512', '_sin', '_sqrt', '_test', '_test_generator', '_urandom', '_warn', 'betavariate', 'choice', 'expovariate', 'gammavariate', 'gauss', 'getrandbits', 'getstate', 'lognormvariate', 'normalvariate', 'paretovariate', 'randint', 'random', 'randrange', 'sample', 'seed', 'setstate', 'shuffle', 'triangular', 'uniform', 'vonmisesvariate', +'weibullvariate'] +``` +Viele dieser Sachen sind allerdings ersteinmal uninteressant, deshalb wollen wir uns daher ersteinmal auf folgende Dinge beschränken: + +* choice +* gauss +* randint +* random +* randrange +* sample +* seed +* shuffle + +### random.seed() +Wir wollen dabei mit random.seed() anfangen. Mit dieser Methode können wir den Seed für die Zufallsberechnung setzen. Der Seed wird bei der Zufallsberechnung als Ausgang genommen, was bedeutet, das bei dem selben Seed immer derselbe Strom an Zufallszahlen entstehen wird. Daher ist diese Methode auch essentiell wichtig, da sie die anderen der obigen Methoden beeinflusst. +```python +import random +random.seed("foo") +random.random() # 0.45443115919715416 +random.random() # 0.27540896360984124 +``` +Um Zufall zufällig zu behalten sollte **niemals** ein statischer Seed oder ein sehr primitiver Seed (wie zum Beispiel Datum oder Uhrzeit) benutzt werden. + + +### random.random() +Wir haben eben eine weitere Methode benutzt ohne sie einzuführen. Diese Methode liefert eine Fließkommazahl zwischen 0 und ausschließend 1 zurück. +```python +import random +random.random() +``` + +### random.randint() +Diese Methode erwartet zwei Parameter (einen Startwert und einen Endwert) und gibt eine Zufallszahl zwischen diesen beiden Werten zurück, wobei der Endwert ausgenommen ist. +```python +import random +R = random.randint(0,10) +print(R) +``` +ist äquivalent zu: +```python +import random +R = int(random.random()*10) +``` diff --git a/turtle.md b/turtle.md new file mode 100755 index 0000000..a927ad1 --- /dev/null +++ b/turtle.md @@ -0,0 +1,232 @@ +# Einstieg in turtle +## Vorwort +Im folgenden wird das `turtle`-Modul aus der Standardbibliothek vorgestellt, die Beispiele sind absichtlich einfach gehalten und sollen einen sanften Einstieg gewährleisten. Um den Codebeispielen folgen zu können, solltest du wissen: + +* wie du auf deinem System Pythoncode ausführst +* was eine Variable ist +* was ein Funktionsaufruf ist +* was ein `int`, ein `string` und ein `float`sind +* was eine `if`-Bedingung ist +* was eine Schleife ist + +Solltest du bei einem der oben genannten Punkte noch Fragen oder Probleme haben, schau dir doch mal die Level 0 - 2 an. + +## Das turtle-Modul +Mit dem `turtle` Modul ist es möglich, mit Hilfe von einfachen Befehlen/Funktionen die namensgebende turtle über ein Fläche zu bewegen. +Die turtle zeichnet dabei standardmäßig eine Spur hinter sich, dies kann benutzt werden um einfache bis komplexe Formen auf der 2D-Ebene zu zeichnen. +Das `turtle`-Modul stellt dafür einfache Funktionen bereit, die miteinander verknüpft werden können um die turtle zu bewegen. + +Viele `turtle`-Methoden bieten Aliase an (z.B. `turtle.fd()` statt `turtle.forward()`). Diese Aliase vermindern die Schreibarbeit, leider aber auch die Lesbarkeit. Ob du diese Aliase benutzen willst, um ein paar Zeichen zu sparen, bleibt selbstverständlich dir überlassen. Wir weisen bei den Funktionen auf ihre jeweiligen Aliase hin. + +Im folgenden sollen in kurzen Codeabschnitten, die einzelnen Funktionen vorgestellt werden. Die Codeabschnitte sind so konzipiert, dass sie einfach in den Interpreter oder eine .py-Datei kopiert werden können, ohne auf vorherige Abschnitte angewiesen zu sein. Daher fängt jeder Codeabschnitt auch mit dem `import`-Statement an. + +Für den Anfang kannst du die turtle am einfachsten aus dem Interpreter heraus steuern. Öffne dazu den Python-Interpreter deiner Wahl, importiere die `turtle`-Bibliothek und fang an der turtle Befehle zu geben. Dann sollte sich ein Fenster öffnen, in dem du die turtle beobachten kannst. Die Arbeit im Interpreter hat den Vorteil, dass du die Auswirkungen deines Codes direkt sehen kannst. Es bietet sich also an deinen Python-Interpreter und das turtle-Fenster nebeneinander zu öffnen. + +## Die turtle bewegen +Die `forward()` und `backward()` Methoden können für die Bewegung benutzt werden. Die turtle läuft dabei die angegebene Strecke ab und zieht eine Spur hinter sich her. Dabei ändert sich nicht ihre Richtung. Beim Start des Programms ist die Richtung `0` was nach rechts entspricht. + +Alternativ zu `turtle.forward(n)` kann auch `turtle.fd(n)` und statt +`turtle.backward(n)` `turtle.bk(n)` benutzt werden. +``` python +import turtle +turtle.forward(50) # bewegt die turtle um 50 Pixel nach vorne +turtle.backward(25) # bewegt die turtle um 25 Pixel nach hinten +``` + +Um die turtle zu drehen und somit ihre Richtung zu ändern, gibt es die `left()` und `right()` Methode, welche die turtle um eine bestimmte Grad-Zahl in die entsprechende Richtung drehen. Alternativ zu `left()` und `right()` können auch die Alias-Methoden `lt()` bzw. `rt()` benutzt werden. +``` python +import turtle +turtle.forward(50) # bewegt die turtle um 50px +turtle.left(90) # dreht die turtle um 90° nach links +turtle.forward(20) # bewegt die turtle um 20px +turtle.right(180) # dreht die turtle um 180° nach rechts +turtle.forward(20) # bewegt die turtle um 20px +``` + +## Auslesen von Position und Richtung +Die Methoden `turtle.position()` und `turtle.heading()` liefern uns die aktuelle Position bzw. Richtung der turtle. Diese Methoden können zum Beispiel dabei helfen, nicht über den Rand zu laufen oder eine Kreislinie entlang zu laufen. +``` python +import turtle +turtle.forward(100) # bewegt die turtle um 100px +turtle.left(90) # dreht die turtle um 90° nach links +turtle.forward(50) # bewegt die turtle um 50px + +position = turtle.position() # aktuelle Position +print(position) # Out: (100.00,50.00) + +heading = turtle.heading() # aktuelle Richtung +print(heading) # Out: 90.0 +``` +Alternativ zu `turtle.position()` kann `turtle.pos()` verwendet werden. + +Zusätzlich zu den Methoden `forward()` und `backward()` welche die turtle relativ zu ihrer aktuellen Position bewegen, kann auch die `setposition()` Methode benutzt werden um die turtle unabhängig von ihrer aktuellen Position und Richtung zu einer bestimmten Position zu bewegen. Dabei wird die Richtung beibehalten. +``` python +import turtle +turtle.setposition((100, 0)) # bewegt die turtle zu angegebenen Position +turtle.setposition((100, 100)) +``` +Alternativ zur `setposition()`-Methode können auch die Alias-Methoden `setpos()` oder `goto()` benutzt werden. + +Analog zur `turtle.setposition()`-Methode kann die `turtle.setheading()`-Methode benutzt werden um die Richtung der turtle unabhängig von ihrer aktuellen Richtung zu verändern. Standardmäßig erwartet die Methode eine Grad-Zahl als `int` oder `float`. Hierbei entsprechen 0° nach rechts, 90° nach oben, 180° nach links, 270° nach oben. Es ist allerdings auch möglich negative Werte anzugeben (-90° entspricht nach unten). +``` python +import turtle +print(turtle.heading()) # Out: 0.0 + +turtle.setheading(90) # setzt die Richtung der turtle auf die angegebene Grad-Zahl +turtle.forward(50) + +print(turtle.heading()) # Out: 90.0 +print(turtle.position()) # Out: (0.00, 50.00) +``` +Alternativ zur `setheading()`-Methode kann auch die Alias-Methode `seth()` benutzt werden. + +Eine praktische Methode im Zusammenhang mit Position und Richtung ist die `turtle.home()`-Methode, welche Position und Richtung auf `(0.00, 0.00)` bzw. `0.0` zurücksetzt. + +Mit Hilfe der `distance()`-Methode kann die Entfernung der turtle zum Beispiel zu einer Position berechnet werden. +```python +import turtle +turtle.setposition((100, 100)) +distance = turtle.distance((0, 0)) # berechnet die Distanz zur Position +print(distance) # Out: 141.4213562373095 +``` + +Analog zur `distance()`-Methode kann mit der `towards()`-Methode der Winkel der Linie zwischen der aktuellen Position und der angegebenen Position. +```python +import turtle +turtle.setposition((100, 100)) +gradient = turtle.towards((0, 0)) +print(gradient) +# Out: 225.0 +``` + +## Manipulation der gezogenen Linie +Standardmäßig zeichnet die turtle eine schwarze Linie, wenn sie sich bewegt. Mit `turtle.penup()` und `turtle.pendown()` ist es möglich den *Stift* zu heben un zu senken und somit das Zeichnen der Linie zu unterbrechen. Dies kann sinnvoll sein um die turtle zu einer Ausgangsposition zu bewegen, ohne dabei eine Linie zu ziehen. Gerade in Verbindung mit der `turtle.setposition()`- und der `turtle.home()`-Methode ergibt es Sinn den *Stift* anzuheben. + +Der folgende Codeabschnitt bewegt die turtle zu einer Ausgangsposition `(-100, -100)` und zeichnet anschließend ein Quadrat mit einer Seitenlänge von 200 Pixeln, dessen Mitte bei `(0.00, 0.00)` liegt. +```python +import turtle +turtle.penup() # Stift heben -> keine Linie +turtle.setposition((-100, -100)) # Ausgangsposition +turtle.pendown() # Stift senken -> Linie +for i in range(4): + turtle.forward(200) + turtle.left(90) +``` +Alternativ zu `turtle.penup()` können auch die Alias-Methoden `turtle.pu()` oder `turtle.up()` benutzt werden. Alternativ zu `turtle.pendown()` können auch die Alias-Methoden `turtle.pd()` oder `turtle.down()` benutzt werden. + +Mit Hilfe der `turtle.isdown()`-Methode kann überprüft werden, ob der *Stift* gesenkt ist, also ob gerade eine Linie gezogen wird. +```python +import turtle +turtle.penup() # Stift heben -> keine Linie +pen_status = turtle.isdown() +print(pen_status) +# Out: False + +turtle.pendown() # Stift senken -> Linie +pen_status = turtle.isdown() +print(pen_status) +# Out: True +``` + +Die Farbe der Linie, welche von der turtle gezogen wird, lässt sich mit der `turtle.pencolor()` lesen und verändern. Übergeben wir der Methode keine Parameter, wird die aktuelle Farbe zurückgegeben. Übergeben wir der `turtle.pencolor()`-Methode allerdings einen Parameter, der eine entsprechende Farbe enthält, so nimmt der Stift diese Farbe an. +```python +import turtle +color = turtle.pencolor() +print(color) +# Out: 'black' +turtle.pencolor("red") +turtle.forward(100) +``` + +Es gibt verschiedene Formate der `turtle.pencolor()`-Methode einen Farbparameter zu geben. Im oberen Beispiel wurde ein *color string* benutzt, eine weiteres Format besteht in einem *RGB-tuple* welches die Farbe als Mischung aus **R**ot, **G**rün und **B**lau angibt. +```python +import turtle +turtle.pencolor((255, 0, 0)) # setzen der Farbe mit einem RGB-tuple +turtle.forward(100) +``` + +Weitere Informationen zu den verschiedenen Formaten findest du in der Dokumentation zum `turtle`-Modul: https://docs.python.org/3/library/turtle.html#turtle.pencolor. + +Neben der Stiftfarbe ist es möglich die Stiftbreite zu ändern. Dafür wird die `turtle.pensize()`-Methode benutzt. Der folgende Codeschnippsel zeichnet das Quadrat von weiter oben, diesmal allerdings mit einer größeren Stiftbreite. Ähnlich zur `turtle.pencolor()`-Methode, liest die `turtle.pensize()` den aktuellen Wert aus, sollten keine Parameter übergeben werden und setzt den Wert der Stiftbreite, sollten Parameter übergeben worden sein. +```python +import turtle +pen_size = turtle.pensize() # Auslesen der Stiftbreite +print(pen_size) # Out: 1 + +turtle.pensize(10) # Setzen der Stiftbreite +turtle.penup() # Stift heben -> keine Linie +turtle.setposition((-100, -100)) # Ausgangsposition +turtle.pendown() # Stift senken -> Linie +for i in range(4): + turtle.forward(200) + turtle.left(90) +``` +Alternativ zur `turtle.pensize()`-Methode kann auch die `turtle.width()`-Methode benutzt werden. + +## Flächen füllen +Mit den Methoden `turtle.begin_fill()` und `turtle.end_fill()` ist es möglich, Flächen zu färben, die von der turtle eingeschlossen wurden. Im folgenden Codeausschnitt wird dies (wieder am Beispiel eines Quadrates) demonstriert. Die Methode `turtle.fillcolor()` kann analog zur Methode `turtle.pencolor()` benutzt werden um die entsprechende Farbe festzulegen. Die Methode `turtle.filling()` wird analog zur Methode `turtle.isdown()` benutzt um zu erkennen, ob gerade eine Fläche gefüllt wird. +```python +import turtle +turtle.penup() # Stift heben -> keine Linie +turtle.setposition((-100, -100)) # Ausgangsposition +turtle.pendown() # Stift senken -> Linie +print("filling? ", turtle.filling()) + +turtle.fillcolor("blue") # Setzen der Farbe zum ausfüllen +turtle.begin_fill() # Ausfüllen starten + +for i in range(4): + turtle.forward(200) + turtle.left(90) + print("filling? ", turtle.filling()) + +turtle.end_fill() # Ausfüllen beenden +``` + +Die Methode `turtle.color()` kann benutzt werden um sowohl die *pencolor* als auch die *fillcolor* festzulegen. +```python +import turtle +turtle.color("red", "blue") +print(turtle.pencolor()) # Out: red +print(turtle.fillcolor()) # Out: blue +``` + +## Ändern der Geschwindigkeit +Die Geschwindigkeit der turtle kann mit der `turtle.speed()`-Methode gelesen und geändert werden. Im folgenden Codeausschnitt wird das bereits bekannte Quadrat gezeichnet, jedoch wird beim Zeichnen die Geschwindigkeit von Kante zu Kante variiert. +```python +import turtle +turtle.penup() # Stift heben -> keine Linie +turtle.setposition((-100, -100)) # Ausgangsposition +turtle.pendown() # Stift senken -> Linie +speed = turtle.speed() # Auslesen der Geschwindigkeit +print(speed) # Out: 3 + +for i in range(4): + turtle.forward(200) + turtle.left(90) + turtle.speed(speed + 3) # Setzen des speed-Wertes +``` +Die Geschwindigkeit kann auf zwei Arten angegeben werden: als `int` zwischen `0` und `10` oder als *speed string*. Wird ein Wert `<0.5` oder `>10` übergeben, wird der `speed`-Wert auf `0` gesetzt. Folgende *speed strings* sind möglich: +* `“fastest”: 0` +* `“fast”: 10` +* `“normal”: 6` +* `“slow”: 3` +* `“slowest”: 1` + +## Weitere Funktionen +Das `turtle`-Modul umfasst noch viele weitere Funktionen, sie alle hier aufzulisten wäre müßig und redundant. Du solltest nun die wichtigsten Methoden kennengelernt haben. Gerüstet mit diesen Methoden kannst du jetzt mit dem Modul experimentieren. In diesem Abschnitt folgen noch ein paar weitere Methoden, falls du noch mehr kennenlernen möchtest. Da wir hier nicht alle Methoden vorstellen solltest du trotzdem dir die Dokumentation zum `turtle`-Modul (du findest sie unter: https://docs.python.org/3/library/turtle.html) ansehen, um heraus zu finden, was noch alles möglich ist. + +### Sichtbarkeit der turtle +Mit der Methode `turtle.hideturtle()` lässt sich die turtle verstecken, in der Dokumentation wird erwähnt, das dies die Performanz verbessern kann. Um die turtle wieder sichtbar zu machen, kann die Methode `turtle.showturtle()` verwendet werden. Alternativ können auch die Aliase der Methoden `turtle.ht()` bzw. `turtle.st()` benutzt werden. + +### Bildschirmgröße +Das `turtle`-Modul bietet auch Methoden an auf den Fenster zuzugreifen, in dem sich die turtle bewegt. Beispielsweise kann mit der `turtle.screensize()` die Bildschirmgröße abgerufen und geändert werden. +```python +import turtle +width, height = turtle.screensize() +print(width, height) # Out: 400 300 +turtle.screensize((800, 600)) +``` +Die genaue Größe des Fensters in Pixeln zu kennen, kann hilfreich sein, um zu verhindern, dass die turtle den sichtbaren Bereich verlässt. + +### turtle.Turtle \ No newline at end of file