#!/usr/bin/env python # coding: utf-8 # Python Einführungskurs für das Physikalische Anfängerpraktikum der Universität Heidelberg | [Startseite](index.ipynb) # # --- # # 101 - Grundlagen der Programmierung in Python # - [Aufgabe 1 - Werte und Typen](#Aufgabe-1---Werte-und-Typen) # - [Strings](#Strings) # - [Aufgabe 2 - Strings und Dokumentation](#Aufgabe-2---Strings-und-Dokumentation) # - [Aufgabe 3 - String Formatierung](#Aufgabe-3---String-Formatierung) # - [Listen und Tupel](#Listen-und-Tupel) # - [Slicing](#Slicing) # - [Dictionaries](#Dictionaries) # - [Aufgabe 4 - Dictionaries](#Aufgabe-4---Dictionaries) # Programmieren besteht aus einer Aneinanderreihung von Befehlen, die der Python Interpreter ausführt. Ein einfacher Befehl ist die Zuweisung eines Wertes zu einer **Variablen**: # In[ ]: x = 1 # Diese Zelle auswählen und mit ` + ` ausführen. # Der letzte Rückgabewert der Zelle wird dann unten ausgegeben, # hier also der Wert von `x`: x # > **Hinweis:** Dieses Kursmaterial besteht aus interaktiven [Jupyter Notebooks](http://jupyter.org). Jede _Zelle_, wie die obige, könnt ihr per Klick oder mit den Pfeiltasten auswählen und mit ` + ` ausführen. Probiert's mal mit der Zelle oben! # > # > **Geht, um dem Kurs zu folgen, _alle_ Zellen nacheinander durch und führt sie aus.** # > # > Wie hier demonstriert gibt das Jupyter Notebook immer den letzten Rückgabewert einer Zelle aus. Wir können auch die `print()` Funktion verwenden, um Ausgaben zu generieren: # In[ ]: print(x) # Der **Wert** der Variable `x` ist nun der Integer `1`. Werte haben immer einen **Typ** wie # # - `int` für ganze Zahlen, z.B. `1`, `42`, `-10`, # - `float` für Fließkommazahlen, z.B. `0.5`, `3.14`, `1e10`, # - `str` für Zeichenketten (_Strings_), z.B. `"Hello World!"`, # - `boolean` für Wahrheitswerte (_Booleans_), also `True` und `False` # # > Die Typen der Python Standardlibrary findet ihr in der [Dokumentation](https://docs.python.org/3/library/stdtypes.html). # # Da Variablen in Python nicht typisiert sind, können der gleichen Variable nacheinander Werte verschiedener Typen zugewiesen werden: # In[ ]: type(x) # In[ ]: x = 0.5 type(x) # Weiterhin können Werte in einen anderen Typ konvertiert werden: # In[ ]: x = int(0.5) # Bei der Konvertierung zu int wird immer abgerundet! x # Die grundlegenden Rechenoperationen `+`, `-`, `*`, `/` und `**` sind ebenfalls in Python verfügbar und verhalten sich, wie man es erwartet: # In[ ]: 1 + 3 # In[ ]: 3 / 2 # > **Hinweis zu Python 2.x:** Die Division zweier Integer gab vor Python 3 wieder einen abgerundeten Integer zurück, im obigen Beispiel also `3 / 2 = int(1.5) = 1`. Damit sich die Division mit Python 2.x stattdessen wie in Python 3 verhält, kann diese zu Beginn des Skripts importiert werden: # > # > ```python # > from __future__ import division # > ``` # > # > Die Integer Division ist außerdem in Python 3 als Operator `//` verfügbar: # In[ ]: 3 // 2 # In[ ]: 3**2 # ## Aufgabe 1 - Werte und Typen # # Der Operator zur Potenzierung ist in Python `**`. Weise einer Variablen `y` folgende Werte zu und lasse dir dann ihren Wert und Typ ausgeben. Stimmen Wert und Typ mit deinen Erwartungen überein? # a) $4^3$ # > **Hinweis:** Dies ist eine Übungsaufgabe. Verwende die Zelle unten, um sie zu lösen. **Entferne** dazu den Platzhalter-Code # > # > ```python # > # DEINE LÖSUNG HIER # > ``` # > # > und schreibe stattdessen den Code zur Lösung der Aufgabe. # In[ ]: y = 4**3 y, type(y) # > **Hinweis:** Auf die Lösung jeder Aufgabe folgt eine Test-Zelle wie die folgende, mit der du deine Lösung überprüfen kannst. Führe einfach diese Zelle aus. Wenn etwas an deiner Lösung nicht stimmt, erhälst du eine Fehlermeldung mit Hinweisen. # In[ ]: from nose.tools import assert_equal try: y except NameError: raise NameError("Es gibt keine Variable 'y'. Weise den Wert einer Variablen mit diesem Namen zu.") assert_equal(y, 64, "Die Variable hat nicht den richtigen Wert. Überprüfe deine Rechnung.") print("👍 Sehr gut!") # b) $2+3.4^2$ # In[ ]: y = 2 + 3.4**2 y, type(y) # In[ ]: from nose.tools import assert_equal try: y except NameError: raise NameError("Es gibt keine Variable 'y'. Weise den Wert einer Variablen mit diesem Namen zu.") assert_equal(y, 2 + 3.4**2, "Die Variable hat nicht den richtigen Wert. Überprüfe deine Rechnung.") print("Ok, du hast es verstanden.") # ## Strings # Strings sind **Zeichenketten** wie: # In[ ]: s = "Hello World" # und werden in Python vom Typ `str` repräsentiert. Um einen String zu erstellen können wir einzelne (`'`), doppelte (`"`) oder dreifache (`'''` oder `"""`, für mehrzeilige Strings) Anführungszeichen verwenden, sodass das jeweils andere Anführungszeichen im String verwendet werden kann: # In[ ]: s.count() # In[ ]: "I'm" # Alternativ können Steuerzeichen im String auch _escaped_ werden: # In[ ]: "Say \"hi\"" # ### Strings sind Reihen # Da Strings eine Aneinanderreihung von Elementen (in diesem Fall Textzeichen) darstellen, können viele Funktionen mit Strings verwendet werden, die mit **Reihen** arbeiten. Dazu gehören: # In[ ]: len(s) # gibt die Zahl der Reihenelemente zurück # In[ ]: s[0] # gibt das Element der Reihe an der Stelle 0 zurück # In[ ]: s + "!" # Reihen können kombiniert werden # ### Strings sind Objekte # Die meisten "Dinge" in Python sind **Objekte**, d.h. neben ihrem Typ besitzen sie assoziierte **Attribute** und **Methoden**, auf die über einen Punkt `.` zugegriffen werden kann. Neben Strings sind bspw. auch Werte der anderen schon bekannten Datentypen wie `int(5)` und sogar Funktionen und die Datentypen selbst Objekte. # # Ein Attribut eines Objekts ist eine Variable, die gelesen und gesetzt werden kann, wie bspw. `x.shape`. Eine Methode ist eine Funktion, die das Objekt zur Verfügung stellt, wie `x.min()`. # # Einige Beispiele für Methoden, die Strings zur Verfügung stellen, sind: # In[ ]: s.upper() # In[ ]: s.split() # In[ ]: s.index('World') # > **Hinweis:** In Jupyter Notebooks können wir die **``-Vervollständigung** verwenden um die assoziierten Attribute und Methoden eines Objekts zu inspizieren: # > # > ```python # > s = "Hello World" # > # Zelle ausführen, dann: # > s. # `s.` tippen und die -Taste drücken # > ``` # > # > Dies zeigt die verfügbaren Attribute und Methoden des Strings `s` an. Die ``-Vervollständigung für eine Variable funktioniert erst nachdem die Variable erstellt wurde, also die Zelle einmal ausgeführt wurde. # > # > Um herauszufinden, was eine Funktion oder Methode tut, könnt ihr im Jupyter Notebook ein Fragezeichen `?` verwenden: # > # >```python # >In [1]: s.split? # >``` # >```markdown # >Docstring: # >S.split(sep=None, maxsplit=-1) -> list of strings # > # >Return a list of the words in S, using sep as the # >delimiter string. If maxsplit is given, at most maxsplit # >splits are done. If sep is not specified or is None, any # >whitespace string is a separator and empty strings are # >removed from the result. # >Type: builtin_function_or_method # >``` # > # > Schreibt ihr stattdessen zwei Fragezeichen `??` zeigt das Jupyter Notebook die gesamte Definition der Funktion oder Methode an. # > # > **Verwendet die ``-Vervollständigung und die `?`-Dokumentation häufig um hilfreiche Attribute und Methoden zu finden und zu verstehen!** # ## Aufgabe 2 - Strings und Dokumentation # # Finde im folgenden String mithilfe einer Methode, wie häufig der Buchstabe `"A"` auftaucht und weise den Wert einer Variable `n` zu. Probiere die ``-Vervollständigung und die `?`-Dokumentation aus um eine passende Methode zu finden. # In[ ]: s = "CAGTACCAAGTGAAAGAT" ### BEGIN SOLUTION n = s.count("A") ### END SOLUTION print(n) # In[ ]: from nose.tools import assert_equal try: y except NameError: raise NameError("Es gibt keine Variable 'n'. Weise den Wert einer Variablen mit diesem Namen zu.") assert_equal(n, 8, "Das ist nicht die richtige Anzahl. Versuch's mal mit der `count` Methode!") print("Klappt!") # ### String-Formatierung # # Eine wichtige Methode ist `str.format()`, die markierte Platzhalter im String mit Werten ersetzt, die der Methode übergeben werden: # In[ ]: x = 10 "Der Wert von x ist {}".format(x) # Ein Platzhalter wird durch eine öffnende `{` und schließende `}` geschweifte Klammer begrenzt und kann eine Bezeichnung des Platzhalters sowie Formatierungsoptionen beinhalten: # In[ ]: "{raw_value} ist gerundet {rounded_value:.3f}.".format(raw_value=2/3, rounded_value=2/3) # > **Hinweis:** Die vollständige Syntax der String-Formatierung ist in der [Dokumentation](https://docs.python.org/2/library/string.html#format-string-syntax) einzusehen. # ## Aufgabe 3 - String Formatierung # # Schreibe deinen Namen in die Variable `name`. Verwende dann die `format` Methode um aus `s` und `name` den Gruß `"Hello World, mein Name ist __DEIN_NAME__!"` zusammenzusetzen. Weise den zusammengesetzten String der Variable `greeting` zu. # In[ ]: s = "Hello World" name = "__DEIN_NAME__" ### BEGIN SOLUTION greeting = s + ", mein Name ist {name}!".format(name=name) ### END SOLUTION print(greeting) # In[ ]: from nose.tools import assert_in try: greeting except NameError: raise NameError("Es gibt keine Variable 'greeting'. Weise den Wert einer Variablen mit diesem Namen zu.") assert_in("mein Name ist", greeting) print("Hello {}! 👋".format(name)) # ## Listen und Tupel # # Während Strings einzelne Zeichen aneinanderreihen, repräsentieren **Listen** und **Tupel** eine Reihe _beliebiger_ Werte. Die Elemente einer Liste können verändert werden, während ein Tupel unveränderlich ist. Wir können Listen erstellen, indem wir die Elemente durch Kommata getrennt in eckigen Klammern `[` und `]` angeben, und Tupel durch die Verwendung runder Klammern `(` und `)`: # In[ ]: l = [ 4, 0.5, "Alice" ] l # In[ ]: t = ( "Bob", True ) t # ### Auch Listen und Tupel sind Reihen # # Wie bei jeder Reihe können wir die Anzahl der Elemente bestimmen und auf einzelne Elemente über ihren Index zugreifen: # In[ ]: len(l), len(t) # In[ ]: l[0] # Indexierung beginnt in Python mit dem Index 0 # In[ ]: l[1] # In[ ]: l[2] # In[ ]: t[0] # In[ ]: t[1] # ### Listen sind veränderlich # Anders als Strings und Tupel können Listen jedoch verändert werden, indem Elemente verändert, hinzugefügt oder entfernt werden: # In[ ]: l[1] = -2.2 # Weise der Liste einen neuen Wert beim Index 1 zu l # In[ ]: l.append(-3) # Füge einen neuen Wert am Ende der liste hinzu l # In[ ]: l.pop() # Entfernt das letzte Element (bzw. das am angegebenen Index) aus der Liste und gibt es zurück # ## Slicing # # Du kannst mit der _Slicing_ Syntax auf Teile einer Reihe zugreifen: # # ```python # slice = list[start:stop:step] # ``` # # Dabei bezeichnet `start` den ersten Index und `stop` den letzten nicht mehr enthaltenen Index des Abschnitts. Mit `step` kannst du eine Schrittweite angeben, in der die Reihe iteriert werden soll. # # Du musst nicht alle drei Argumente angeben. Per default ist dann `start=0`, `stop=len(list)` und `step=1`: # In[ ]: l[:2] # Der erste Index ist per default start=0 # In[ ]: l[2:] # Der letzte Index ist per default das Ende der Reihe # In[ ]: l[::2] # Jedes zweite Element # In[ ]: l[::-1] # Umgekehrte Reihenfolge # > **Hinweis:** Slicing ist ein mächtiges Werkzeug um kurzen, prägnanten Code zu schreiben und wird dir bei der Arbeit mit _Numpy Arrays_ ab Lektion [201 - Numerik mit Numpy](201 - Numerik mit Numpy.ipynb) noch sehr häufig begegnen. # ## Dictionaries # # Ein weiterer wichtiger Datentyp ist das **Dictionary**. Ein Dictionary ordnet jeweils einem _Key_ einen _Value_ zu und wird durch geschweifte Klammern `{` und `}` erstellt: # In[ ]: d = { 'a':1, 'b':2, 'c':3 } d # Auf einzelne Werte kann über ihren Key zugegriffen werden: # In[ ]: d['a'] # Dictionaries sind veränderlich wie Listen: # In[ ]: d['d'] = 4 d # Es müssen nicht unbedingt Strings als Keys verwendet werden, und auch verschiedene Datentypen sind möglich: # In[ ]: e = { 'some_key': 4.2, 3517: 'some_value' } e # In[ ]: e['some_key'] # In[ ]: e[3517] # ## Aufgabe 4 - Dictionaries # # Schreibe ein Wörterbuch mit einigen deutschen Wörtern und ihrer Übersetzung ins Englische. Weise es der Variable `d` zu und verwende es dann, indem du dir einige Werte darin ausgeben lässt. # In[ ]: ### BEGIN SOLUTION d = { "Wörterbuch": "dictionary" } ### END SOLUTION d["Wörterbuch"] # In[ ]: from nose.tools import assert_true try: d except NameError: raise NameError("Es gibt keine Variable 'd'. Weise den Wert einer Variablen mit diesem Namen zu.") assert_true(len(d) > 0, "Das Wörterbuch hat keine Einträge.") print("Wow, {} Einträge im Wörterbuch!".format(len(d))) # --- # # Du kannst nun mit Variablen und Datentypen umgehen und den Python Interpreter rechnen lassen. Lerne in der nächsten Lektion, wie du mit _Control Flow_ Anweisungen deine ersten Programme schreiben kannst. # # [Startseite](index.ipynb) | [**>> 102 - Control Flow**](102%20-%20Control%20Flow.ipynb)