6 Grundlegende Sprachelemente¶
6.1 Syntax und Semantik¶
Zur Syntax mit der Einrückung …¶
[1]:
variable = 666
if variable == 666:
print('jo super')
print('noch besser')
jo super
noch besser
In C zum Beispiel geht das so (wobei hier die Einrückung irrelevant ist):
void f() {
int variable = 666;
/* ... */
}
In Python können Variablen ihren Typ ändern¶
[2]:
variable = 666
print(type(variable))
variable = 3.14
print(type(variable))
variable = 'Ein depperter String'
print(type(variable))
<class 'int'>
<class 'float'>
<class 'str'>
Sidestep: selbst Funktionen sind Objekte, halt eben vom Typ “Function” und nicht z.B. int
[3]:
type(print)
[3]:
builtin_function_or_method
print
ist nur ein Name für ein Funktionsobjekt. Eine Variable sozusagen. Diese kann man genauso zuweisen und verwenden (aufrufen, in diesem Fall).
[4]:
variable = print
variable('Hello World!')
Hello World!
Kommentare¶
[5]:
zaehler = 0
print('initialwert ist', zaehler)
# jetzt zaehlen wir von 0 bis 9
while zaehler < 10:
print(zaehler)
# hier bereiten wir den naechsten schleifendurchlauf vor
zaehler = zaehler + 1 # oder auch: zaehler += 1
print('fertig')
initialwert ist 0
0
1
2
3
4
5
6
7
8
9
fertig
6.2 Grundlegende Elemente einer Sprache¶
6.3 Standarddatentypen (elementare Datentypen)¶
Integers sind beliebig gro߶
Dieser hier passt locker in ein 64 Bit CPU Register
[6]:
mein_integer = 2**10
print(mein_integer)
1024
Dieser hier gerade noch. Um eins mehr und er wäre dort wieder 0.
[7]:
2**64-1
[7]:
18446744073709551615
Python schützt mich vor solchen Overflow-Bugs, indem Zahlen, die nicht in die CPU passen, in Software gehandhabt werden.
[8]:
2**64
[8]:
18446744073709551616
[9]:
2**100
[9]:
1267650600228229401496703205376
2 hoch 1000 passt in keine CPU.
[10]:
2**1000
[10]:
10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376
Vergleichsoperatoren¶
[11]:
1 == 2
[11]:
False
[12]:
42 == 42
[12]:
True
[13]:
if 42 == 42:
print('eh klar')
eh klar
[14]:
1 < 2
[14]:
True
[15]:
1 <= 2
[15]:
True
[16]:
1 != 2
[16]:
True
Operator Präzedenz: Punkt vor Strichrechnung¶
[17]:
1 + 2 * 3
[17]:
7
[18]:
(1 + 2) * 3
[18]:
9
Floor Division¶
[19]:
1/2
[19]:
0.5
[20]:
3/2
[20]:
1.5
In C ist aber 3/2 == 1
!!! Rechnen tut dort ausschliesslich die CPU, und 3/2
ist eine Ganzzahldivision mit einem ganzzahligen Resultat.
[21]:
3//2
[21]:
1
Modulo Operator: %¶
Rest einer ganzzahligen Division
[22]:
9%2
[22]:
1
[23]:
11%2
[23]:
1
[24]:
9%3
[24]:
0
[25]:
9%5
[25]:
4
[26]:
variable = 42
if variable % 2 == 0:
print(variable, 'ist gerade')
42 ist gerade
(Unärer) Negations Operator¶
[27]:
variable = 42
variable = -variable
[28]:
variable
[28]:
-42
Operator Präzedenz erzwingen¶
und % haben gleichen Vorrang
[29]:
2 * 9 % 5
[29]:
3
[30]:
2 * (9 % 5)
[30]:
8
[31]:
(2 * 9) % 5
[31]:
3
Strings gibts auch (Zeichenketten)¶
[32]:
s = "abc"
print(s)
abc
[33]:
s = 'abc'
print(s)
abc
[34]:
# das da geht nicht: s = "abc"def"
[35]:
s = 'abc"def'
print(s)
abc"def
[36]:
s = "abc'def"
print(s)
abc'def
[37]:
s = "abc\"def'ghi"
print(s)
abc"def'ghi
Multiline Strings
[38]:
s = '''Hallo
Welt,
wie geht's denn so?
Hier ist eine vierte Zeile auch noch.
'''
print(s)
Hallo
Welt,
wie geht's denn so?
Hier ist eine vierte Zeile auch noch.
[39]:
s = 'Hallo\nWelt,\nwie geht\'s denn so?\n'
print(s)
Hallo
Welt,
wie geht's denn so?
Raw Strings¶
\n
ist ein Linefeed. \P
und \M
haben keine spezielle Bedeutung und bleiben unangetastet.
[40]:
path = 'C:\Programme\Mein Glump\nebenlaeufigkeitsdemo'
print(path)
C:\Programme\Mein Glump
ebenlaeufigkeitsdemo
Raw Strings sind dafür die Lösung.
[41]:
path = r'C:\Programme\Mein Glump\nebenlaeufigkeitsdemo'
print(path)
C:\Programme\Mein Glump\nebenlaeufigkeitsdemo
f-Strings¶
f-Strings gibts ab Python 3.6: sehr feine Formatierungsmöglichkeit.
[42]:
var1 = 'hallo'
var2 = 'hello'
pfx_var1 = 'var1='
pfx_var2 = 'var2='
[43]:
ausgabe = pfx_var1+var1+', '+pfx_var2+var2
print(ausgabe)
var1=hallo, var2=hello
[44]:
var1 = 42
var2 = 666
pfx_var1 = 'var1='
pfx_var2 = 'var2='
[45]:
ausgabe = pfx_var1+str(var1)+', '+pfx_var2+str(var2)
print(ausgabe)
var1=42, var2=666
Bessere Formatierung: nicht potschert, mit f-String (seit Python 3.6)
[46]:
var1 = 'hallo'
var2 = 'hello'
ausgabe = f'var1={var1}, var2={var2}'
print(ausgabe)
var1=hallo, var2=hello
[47]:
var1 = 42
var2 = 666
print(f'var1={var1}, var2={var2}')
var1=42, var2=666
Konvertierungen¶
[48]:
s = '666'
type(s)
[48]:
str
[49]:
i = int(s)
print(i)
666
[50]:
try: # notwendig, um jupyter notebook nicht abzubrechen. bitte ignorieren
s = 'abc'
i = int(s)
except ValueError as e:
print(e)
invalid literal for int() with base 10: 'abc'
[51]:
s = '42.666'
f = float(s)
print(f)
42.666
[52]:
s = '10'
i = int(s, 16)
print(i)
16
Boolean¶
[53]:
1 < 2
[53]:
True
[54]:
2 < 1
[54]:
False
[55]:
b = True
print(type(b))
<class 'bool'>
Zum Beispiel:
[56]:
liste = [3,2,1,4]
gefunden = False
for wert in liste:
if wert == 4:
gefunden = True
print(gefunden)
True
Präzendenzregeln: and
vor or
¶
[57]:
True and False
[57]:
False
[58]:
True or False
[58]:
True
[59]:
True and True
[59]:
True
[60]:
False and True
[60]:
False
[61]:
True or False and True
[61]:
True
[62]:
False and True or False
[62]:
False
ist das gleiche wie:
[63]:
(False and True) or False
[63]:
False
[64]:
True and False or True
[64]:
True
ist das gleiche wie:
[65]:
(True and False) or True
[65]:
True
6.4 Literale für primitive Datentypen¶
6.5 Variablen und Konstanten¶
6.6 Operatoren¶
6.7 Ausdrücke und Operatorrangfolgen¶
6.8 Übungen¶
Zwei Variablen vertauschen¶
[66]:
var1 = 42
var2 = 666
[67]:
tmp = var1
var1 = var2
var2 = tmp
[68]:
print('var1:', var1, 'var2:', var2)
var1: 666 var2: 42
Zwei Variablen vertauschen mit Tuple Unpacking¶
[69]:
var1 = 42
var2 = 666
[70]:
var1, var2 = var2, var1
[71]:
print('var1:', var1, 'var2:', var2)
var1: 666 var2: 42
Übung 1, 5.¶
[72]:
value1 = 501
value2 = 799
value3 = 400
[73]:
(value1 > 500) or (value2 < 800) and not (value3 == 400)
[73]:
True
[74]:
(value1 > 500) or ((value2 < 800) and not (value3 == 400))
[74]:
True
7 Kontrollstrukturen¶
7.1 Anweisungen und Folgen¶
7.2 Bedingungen und Kontrollstrukturen¶
7.3 Grundlagen zu Verzweigungen¶
7.4 Bedingte Anweisung¶
7.5 Verzweigung¶
7.6 Geschachtelte Verzweigung¶
7.7 Mehrfache Verzweigung (Fallauswahl)¶
7.8 Schleifen¶
7.9 Zählergesteuerte Schleifen (Iteration)¶
7.10 Kopfgesteuerte bedingte Schleife¶
7.11 Fußgesteuerte bedingte Schleife¶
(jf) break
und continue
¶
(jf) Sequential Datatypes¶
[75]:
s = "Hello World"
[76]:
len(s)
[76]:
11
In Python beginnt man bei 0. In C, Java und C# (und vielen anderen Sprachen) auch.
[77]:
s[1]
[77]:
'e'
[78]:
s[0]
[78]:
'H'
[79]:
s[10]
[79]:
'd'
Negative Indizes erscheinen komisch, sind aber logisch.
[80]:
s[len(s)-1]
[80]:
'd'
[81]:
s[-1]
[81]:
'd'
[82]:
l = ['erstes element', 2, 'drei']
[83]:
l[0]
[83]:
'erstes element'
[84]:
l[-1]
[84]:
'drei'
(jf) for
Loops¶
[85]:
s = 'Hello World'
Bequem:
[86]:
for character in s:
print(character)
H
e
l
l
o
W
o
r
l
d
[87]:
i = 0
while i < len(s):
print(s[i])
i += 1
H
e
l
l
o
W
o
r
l
d
Umständlich:
[88]:
l = ['erstes element', 2, 'drei']
for element in l:
print(element)
erstes element
2
drei
Iteration mit Dictionaries¶
[89]:
mapping_table = {
'null': 'zero',
'eins': 'one',
'zwei': 'two',
'drei': 'three',
'vier': 'four',
'fünf': 'five',
'sechs': 'six',
'sieben': 'seven',
'acht': 'eight',
'neun': 'nine',
}
[90]:
mapping_table['sieben']
[90]:
'seven'
[91]:
mapping_table['zehn'] = 'ten'
[92]:
mapping_table['zehn']
[92]:
'ten'
Iteration über ein Dictionary and sich iteriert über die Keys.
[93]:
for e in mapping_table:
print(e)
null
eins
zwei
drei
vier
fünf
sechs
sieben
acht
neun
zehn
Explicit is better than implicit.
[94]:
for e in mapping_table.keys():
print(e)
null
eins
zwei
drei
vier
fünf
sechs
sieben
acht
neun
zehn
Iteration über die Values.
[95]:
for e in mapping_table.values():
print(e)
zero
one
two
three
four
five
six
seven
eight
nine
ten
Iteration über Key/Value Paare: Tuple
[96]:
for e in mapping_table.items():
print(e)
('null', 'zero')
('eins', 'one')
('zwei', 'two')
('drei', 'three')
('vier', 'four')
('fünf', 'five')
('sechs', 'six')
('sieben', 'seven')
('acht', 'eight')
('neun', 'nine')
('zehn', 'ten')
Manuelles Tuple Unpacking
[97]:
for e in mapping_table.items():
key = e[0]
value = e[1]
print(f'key={key}, value={value}')
key=null, value=zero
key=eins, value=one
key=zwei, value=two
key=drei, value=three
key=vier, value=four
key=fünf, value=five
key=sechs, value=six
key=sieben, value=seven
key=acht, value=eight
key=neun, value=nine
key=zehn, value=ten
Tuple Unpacking mit Hilfe der Sprache
[98]:
for key, value in mapping_table.items():
print(f'key={key}, value={value}')
key=null, value=zero
key=eins, value=one
key=zwei, value=two
key=drei, value=three
key=vier, value=four
key=fünf, value=five
key=sechs, value=six
key=sieben, value=seven
key=acht, value=eight
key=neun, value=nine
key=zehn, value=ten
Ausflug: Vertauschen von zwei Variablen
[99]:
var1 = 666
var2 = 42
Potschert:
[100]:
tmp = var1
var1 = var2
var2 = tmp
print(f'var1={var1}, var2={var2}')
var1=42, var2=666
Mit Tuple Unpacking:
[101]:
var1, var2 = var2, var1
print(f'var1={var1}, var2={var2}')
var1=666, var2=42
(jf) The range()
Function¶
Primzahlen checken, der Algorithmus: 1 ist keine Primzahl Sonst: von 2 bis eins unter der zu checkenden Zahl, probiere alle durch, ob die net gach ein Teiler der zu checkenden Zahl ist.
[102]:
zahl = 15
teiler_kandidaten = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
for n in teiler_kandidaten:
if zahl % n == 0:
print('nicht prim')
break
else:
print('prim')
nicht prim
Wenn ich jetzt zum Beispiel die Zahl 7, und nicht 15, checken will, muss ich gleichemaßen die teiler_kandidaten
ändern.
[103]:
zahl = 7
teiler_kandidaten = [2, 3, 4, 5, 6]
for n in teiler_kandidaten:
if zahl % n == 0:
print('nicht prim')
break
else:
print('prim')
prim
Raymond Hettinger: “There must be a better way”
[104]:
zahl = 15
for n in range(2, zahl):
if zahl % n == 0:
print('nicht prim')
break
else:
print('prim')
nicht prim
Der Vollständigkeit halber (steht in der Doku auf python.org): was kann range()
noch?
[105]:
for i in range(10):
print(i)
0
1
2
3
4
5
6
7
8
9
Das gleiche, explizit mit 0 startend
[106]:
for i in range(0, 10):
print(i)
0
1
2
3
4
5
6
7
8
9
[107]:
for i in range(2, 10):
print(i)
2
3
4
5
6
7
8
9
Von inklusive 2 bis exklusive 15, Schrittweite 3
[108]:
for i in range(2, 15, 3):
print(i)
2
5
8
11
14
7.12 Schnellübersicht¶
7.13 Sprunganweisungen¶
7.14 Endlosschleifen¶
7.15 Übungen¶
8 Elementare Datenstrukturen¶
8.1 Warum werden Datenstrukturen benötigt?¶
(jf) Compound Datatypes¶
(jf) References, (Im)mutability¶
Variable a
referenziert ein Objekt vom Typ int
mit Wert 42
[109]:
a = 42
[110]:
hex(id(a))
[110]:
'0x7f24f2ac0e50'
b
zeigt auf das selbe Objekt (gleiche ID)
[111]:
b = a
[112]:
hex(id(b))
[112]:
'0x7f24f2ac0e50'
int
is immutable, deswegen muss +=
ein neues Objekt ablegen
[113]:
b += 1
[114]:
hex(id(b))
[114]:
'0x7f24f2ac0e70'
[115]:
b
[115]:
43
[116]:
a
[116]:
42
[117]:
hex(id(b))
[117]:
'0x7f24f2ac0e70'
[118]:
hex(id(a))
[118]:
'0x7f24f2ac0e50'
(jf) Laufzeitverhalten bei der Suche (der in
Operator)¶
Liste¶
Suche in einer Liste kann nur sequentielle Suche sein. Arschlangsam.
[119]:
l = [4, 7, 1, 2, 89, 1, 5]
[120]:
key = 5
num_comparisons = 0
for element in l:
num_comparisons += 1
if element == key:
print('gefunden')
break
else:
print('nicht gefunden')
print(f'num_comparisons={num_comparisons}')
gefunden
num_comparisons=7
Der in
Operator macht das bequemer. Aber Vorsicht mit Listen, wie gesagt.
[121]:
5 in l
[121]:
True
Set¶
set
ist eine Datenstruktur, die für schnelles Suchen, Einfügen und Löschen optimiert ist. Perfekt für den in
Operator.
[122]:
s = {4, 7, 1, 2, 89, 1, 5}
5 in s
[122]:
True
8.2 Arrays¶
8.3 Eindimensionale Arrays¶
8.4 Records¶
8.5 Zeichenketten¶
8.6 Tupel und Listen¶
[123]:
l = [1, 'zwei', 3]
[124]:
l.append('vier')
l
[124]:
[1, 'zwei', 3, 'vier']
Einitreten zwischen ‘zwei’ und 3:
[125]:
l.insert(2, 'einitreten')
l
[125]:
[1, 'zwei', 'einitreten', 3, 'vier']
Tuple mit einem Element (Jo Himmi!)
[126]:
t = ('ein element')
t
[126]:
'ein element'
[127]:
type(t)
[127]:
str
[128]:
t = ('ein element',)
Der Hintergrund (Operator Präzedenz)
[129]:
1 + 2 * 3
[129]:
7
[130]:
(1 + 2) * 3
[130]:
9
[131]:
(1+2)
[131]:
3
sorted, reversed¶
[132]:
l = [1, 2, 3]
[133]:
reversed(l)
[133]:
<list_reverseiterator at 0x7f24ec31d190>
[134]:
for elem in reversed(l):
print(elem)
3
2
1
[135]:
l = [3, 2, 4, 6, 1]
[136]:
sorted(l)
[136]:
[1, 2, 3, 4, 6]
[137]:
for elem in sorted(l):
print(elem)
1
2
3
4
6
List Comprehension¶
[138]:
def squares(l):
result = []
for elem in l:
result.append(elem**2)
return result
meine_liste = [1, 2, 3, 4, 5, 6, 7, 8]
for elem in squares(meine_liste):
print(elem)
1
4
9
16
25
36
49
64
[139]:
meine_liste = [1, 2, 3, 4, 5, 6, 7, 8]
for elem in [elem**2 for elem in meine_liste]:
print(elem)
1
4
9
16
25
36
49
64
[140]:
meine_liste = [1, 2, 3, 4, 5, 6, 7, 8]
for elem in [elem**2 for elem in meine_liste if elem % 2 == 0]:
print(elem)
4
16
36
64
8.7 Dictionaries¶
[141]:
mapping_table = {
'null': 'zero',
'eins': 'one',
'zwei': 'two',
'drei': 'three',
'vier': 'four',
'fünf': 'five',
'sechs': 'six',
'sieben': 'seven',
'acht': 'eight',
'neun': 'nine',
}
[142]:
mapping_table['eins']
[142]:
'one'
[]
bricht beinhart mit einer Exception (KeyError
) ab, wenn das ELement nicht existiert.
[143]:
try: # necessary to keep jupyter notebook going
mapping_table['elf']
except Exception as e:
print(type(e), e)
<class 'KeyError'> 'elf'
get()
hingegen liefert None
, wenn das ELement nicht existiert. Je nachdem, wie man es lieber hat.
[144]:
value = mapping_table.get('neun')
if value is None:
print('nicht gefunden')
else:
print(f'gefunden, wert {value}')
gefunden, wert nine
[145]:
value = mapping_table.get('zehn')
if value is None:
print('nicht gefunden')
else:
print(f'gefunden, wert {value}')
nicht gefunden
Der zweite Parameter wird returned, wenn das Element nicht existiert.
[146]:
value = mapping_table.get('zehn', 'jessas')
value
[146]:
'jessas'
(jf) Records in Python¶
8.8 Mengen¶
8.9 Besondere Datenstrukturen anhand von Stapel (Stack) und Schlangen (Queue)¶
8.10 Übungen¶
Übung 1¶
[147]:
numbers = (0, 10, 12, 4, 7, 20, 21, 13)
Versuch 1: in
und index()
¶
[148]:
zahl = 20
[149]:
if zahl in numbers:
pos = numbers.index(zahl)
print(f'{zahl} gefunden, position {pos}')
else:
print('nicht gefunden')
20 gefunden, position 5
Versuch 2: Zurück zu while
…¶
[150]:
i = 0
while i < len(numbers):
if numbers[i] == zahl:
print(f'gefunden, position {i}')
break
i += 1
else:
print('nicht gefunden')
gefunden, position 5
Versuch 3: hybrid potschert mit for
¶
[151]:
pos = 0
for elem in numbers:
if elem == zahl:
print(f'gefunden, position {pos}')
break
pos += 1
else:
print('nicht gefunden')
gefunden, position 5
Versuch 4: supergscheit mit for
und enumerate()
¶
[152]:
for pos, elem in enumerate(numbers):
if elem == zahl:
print(f'gefunden, position {pos}')
break
else:
print('nicht gefunden')
gefunden, position 5
9 Methoden, Prozeduren und Funktionen¶
[153]:
def maximum(a, b):
if a < b:
return b
else:
return a
[154]:
print(maximum(42, 666))
666
Funktionspointer (so heissts in C): Funktionsobjekte (Python)¶
Funktionen sind in Wirklichkeit nur Namen für Funktionsobjekte. Ordinäre Variablen, die man zuweisen etc. kann.
[155]:
print(type(maximum))
<class 'function'>
[156]:
blah = maximum
[157]:
print(type(blah))
<class 'function'>
Aufruf des Funktionsobjektes, auf das auch maximum
zeigt. Nur halt über den alternativen Namen blah
.
[158]:
print(blah(42, 666))
666
(jf) Primzahlenbeispiel mit Funktion¶
[159]:
def is_prime(num):
# low hanging fruit
if num == 1:
return False
# gemmas an
for divisor_candidate in range(2, num//2+1):
if num % divisor_candidate == 0:
return False
else:
return True
n = 1
print(f'{n} prime: {is_prime(n)}')
n = 2
print(f'{n} prime: {is_prime(n)}')
n = 3
print(f'{n} prime: {is_prime(n)}')
n = 4
print(f'{n} prime: {is_prime(n)}')
n = 11
print(f'{n} prime: {is_prime(n)}')
1 prime: False
2 prime: True
3 prime: True
4 prime: False
11 prime: True
(jf) Local vs. Global Scope¶
Laufzeitfehler: Variable existiert nicht¶
[160]:
def f():
print(x)
[161]:
try: # wegen jupyter notebook
f()
except Exception as e:
print(e)
name 'x' is not defined
Lokale Variable¶
Dogma: wenn an einen Namen zugewiesen wird, der im aktuellen Context (“wir sind in Funktion f
”) noch nicht existiert, wird in eben diesem Context dieser Name (diese Variable) erzeugt.
[162]:
def f(param):
meine_variable = param * 7
print(meine_variable)
f(5)
35
Globale Variable (lesen)¶
[163]:
def f():
print(eine_variable)
[164]:
eine_variable = 666
f()
666
Globale Variable (schreiben/zuweisen)¶
Hier wird eine lokale Variable angelegt, die nichts mit der globalen zu tun hat. Streng nach obigem Dogma.
[165]:
eine_variable = 7
def f():
eine_variable = 666
print(f'local: {eine_variable}')
f()
print(f'global: {eine_variable}')
local: 666
global: 7
Wenn man eine globale Variable will, muss man es extra dazusagen. Nicht wie in Javascript.
[166]:
eine_variable = 7
def f():
global eine_variable
eine_variable = 666
print(f'local: {eine_variable}')
f()
print(f'global: {eine_variable}')
local: 666
global: 666
Fehlerfall von Peter¶
[167]:
noch_eine_globale_variable = 42
[168]:
def increment_diese_variable():
noch_eine_globale_variable = noch_eine_globale_variable + 1
[169]:
try: # wegen jupyter notebook schon wieder
increment_diese_variable()
except Exception as e:
print(e)
local variable 'noch_eine_globale_variable' referenced before assignment