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