Eine ganz einfache Variante sind einfache Rechnungen.
In jeder Zelle stehen in oder mehrere Zeilen Programmcode, die mittels Shift+Return
ausgewertet werden.
(Ctrl+Return
gibt es auch, es wird hierbei nicht zur nächsten Zelle vorwärts gesprungen)
z.B.:
3 + 8
11
5 + (1 + 5) / 2
8.0
Apropos Sprachversionen: aus "mathematischer" Sicht gibt es bei Divisionen einen entscheidenden Unterschied. In Version 2 ist die Division mit "/
" abrundend auf die nächste Ganzzahl, während in Verion 3 die handelsübliche Interpretation einer Division verwendet wird (abrundend ist "//
").
Mittels "from __future__ import division
" kann in Version 2 das Verhalten von Version 3 erzwungen werden:
9 / 4
2.25
Im Allgmeinen ist es eine gute Idee, diesen Import immer zu aktivieren.
Striktes Abrunden:
9 // 4
2
... und Modulorechnungen mit %
:
9 % 4
1
type(123)
int
type(1.23)
float
type(5.)
float
Brüche mit Fraction
from fractions import Fraction
a = Fraction("33/31003100")
b = Fraction("-9/100000100001")
print(a * b ** 4)
2673/38275585202254501783218213917955539030103719395100
Dezimalzahlen, die nicht die übliche in dem Computer eingebaute fixe
IEEE 754-2008 Genauigkeit haben und eventuelle Rundungsfehler erzeugen,
sondern IEEE 854-1987 für strengere Genauigkeit folgen, mittels Decimal
:
print(1.1 + 2.2 - 3.3)
4.440892098500626e-16
from decimal import Decimal
u = Decimal("1.1") + Decimal("2.2")
v = Decimal("-3.3")
print(u + v)
0.0
mpmath
erlaubt, analytische Ausdrücke auf höherer Genauigkeit auszuwerten
import mpmath as mpm
mpm.mp.dps = 100
a = mpm.mpf("49.00000000000000001")
b = mpm.mpf( "7.00000000000000001")
a / b**2
mpf('0.999999999999999997346938775510204087172011661807580164514785506039150372463854346403284314358813079585')
mpm.sin(mpm.mpf("3.1415926535"))
mpf('0.00000000008979323846264338327938221965910388125990692946182694867743526330407406677351504727435623041438215811254')
Intervallzahlen mit mpmath
's mpi
x = mpm.mpi("1", "2")
y = mpm.mpi("3", "4.5")
z = x * y
print(x, "*", y, "=", z)
[1.0, 2.0] * [3.0, 4.5] = [3.0, 9.0]
Eine ganz wichtige Kategorie von Ausdrücken sind Zeichenketten (engl. "strings"). Diese werden zwischen einfachen oder doppelten Anführungszeichen eingegeben. Später mehr dazu (siehe "Konzept 5: Datenstrukturen"), hier nur ein einfaches Beispiel:
"dies ist eine Zeichenkette"
'dies ist eine Zeichenkette'
Zusammenführen mehrerer Strings
"String1" + "String2"
'String1String2'
Einfügen eines Strings in eine bestehende Zeichenkette (an der Stelle %s
).
Beachte, einfache Anführungszeichen können innerhalb doppelter Anführungszeichen verwendet werden (und umgekehrt).
"Der Name '%s' ist männlich." % "Hubert"
"Der Name 'Hubert' ist männlich."
Formatieren einer Fließkommazahl in einem String (hier mit 3 Nachkommastellen):
"Das Wasser hat %.3f °C" % 3.1415926535
'Das Wasser hat 3.142 °C'
Die Methode .format()
erledigt komplexere Formatierungsaufgaben:
{:>20s}
: string-format, auf mindestens 20 Zeichen breite mit Leerzeichen auffüllen, und ">
" macht es rechtsbündig,{abc:.4f}
: formatiert das Argument abc
als floating-point Zahl mit 4 Nachkommastellen."{:>20s}: {abc:.4f}".format("test", abc = 42)
' test: 42.0000'
Einer der wichtigsten Typen von Ausdrücken sind Vergleichsoperatoren. Das sind tests auf
is
") -- wo die zu vergleichenden Objekte exakt ident sein müssen.
Das heißt, sie sind sich nicht nur ähnlich, sondern liegen jeweils tatsächlich in derselben Stelle des Speichers.==
") -- hier wird, abhängig von der Vergleichsoperation (!), die Gleichheit festgestellt.<
", ">=
", ...) -- test auf Ungleichheit, ebenfalls von der konkreten Implementation des Vergleichsoperators abhängig."abc" is "abc"
True
6 == 2 * 3
True
6 > 10
False
Es ist auch oft möglich -- wenn sinnvoll -- unterschiedliche Typen zu vergleichen:
6.1 < 10 # float mit int
True
Die Quintessenz eines Programmes ist dessen Flexibilität gegenüber Eingaben. Wäre die Eingabe fest vorgegeben, gäbe es nur wenig Gründe das Programm mehr als nur einmal aufzurufen!
Quiz: Gib einen Grund an, warum ein Programm ohne Dateneingabe mehrmals aufgerufen werden könnte?
Antwort:
Zuweisungen passieren so, dass in der Zeile zuerst eine Variable steht,
dann ein Gleichzeitszeichen, und dann ein Ausdruck der Ausgewertet wird.
Hinweis: Der Wert der Variablen x
ist in der darunterliegenden Zelle weiterhin verfügbar.
x = 4
5 * x + 1
21
y = 2 * x + 1
9 - y - x
-4
Wichtig ist, dass die Zuweisung an x
vor dessen Verwendung in der zweiten Zelle passiert.
Eine Variable ohne vorheriger Zuweisung erzeugt einen Fehler:
p + 23
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-27-2fe5b48a1d33> in <module>() ----> 1 p + 23 NameError: name 'p' is not defined
Variablen können (und sollen meistens) mehr als einen Buchstaben haben.
Dabei sind Groß- und Kleinbuchstaben und Zahlen ab dem zweiten Zeichen erlaubt.
Als einziges Sonderzeichen gibt es den _
Unterstrich.
(das gilt für Python in der Sprachversion 2, Version 3 erlaubt mehr Zeichen.)
apfel_preis = 0.99
stueck = 13
preis = stueck * apfel_preis
print(preis)
12.87
Die vorhergehende Zelle definiert mehrere Variablen und berechnet den Preis des Einkaufs.
Das Wort print
mit anschließenden Klammern gibt den Inhalt der Variablen preis
aus
und ist ein Beispiel für den Aufruf einer Funktion.
Wichtig: Es gibt zwischen den Programmiersprachen subtile Unterschiede, wie genau die Bedeutung einer Variablen ist und wie sie sich im Kontext von Ausdrücken verhält.
Bezüglich Python kann man es sich am besten so vorstellen, dass ein Variablenname das Etikett zur Beschriftung einer Box (dem "Wert") ist.
from IPython.display import SVG
from os.path import join
SVG(filename=join('res', 'variable.svg'))
Es kann nämlich auch folgendes passieren:
b=a
, wird zuerst die rechte Seite auf das jeweilige Objekt hinter a
"dereferenziert", und dann b
zugeweisen.None
" Wert)a = 42
b = a
a
42
b
42
Der eingebaute Befehl id
gibt die interne Speicheradresse des Wertes zurück.
Dieser ist hier genau gleich, da es sich um die identischen Objekte im Speicher handelt.
Dies funktioniert mit beliebigen Werten,
jedoch instanzieren wir hier zwei minimale Grundobjekte zur besseren Veranschaulichung:
a = object()
b = object()
id(a), id(b)
(140035719422960, 140035719423008)
a is b
False
Namensänderung: Das Objekt hinter a
wird mittels b = a
nun auch b
genannt.
Das ursprüngliche Objekt hinter b
verschwindet in den Weiten des Arbeitsspeichers (garbage collection), da es keinen Namen mehr hat.
b = a
id(a), id(b)
(140035719422960, 140035719422960)
Die Zuweisung von a
an b
hat somit bewirkt, dass der Wert von a
die Bezeichung b
bekommen hat.
Es ist also weder der Wert von a
nach b
gewandert,
noch wurde eine Kopie erzeugt.
Letzteres kann bei komplexeren Objekten zu subtilen Fehlern führen, aufpassen!
a is b
True