Python fΓΌr UmsteigerΒΆ
print("Hallo Welt")
Γber michΒΆ
- Lehrer an der CWS Usingen (Mathe/Informatik/demnΓ€chst: Darstellendes Spiel)
- Abgeordnet ans Schulportal (Moodle Theme)
- Wir unterrichten an der CWS seit 2018 in GK mit Python
Python in der Sek IIΒΆ
Erfahrungen im Unterricht mit PythonΒΆ
Man redet weniger ΓΌber syntaktische Fehler und ist schneller bei semantischen Fehlern.
SchΓΌler haben mehr Erfolgserlebnisse
Python lΓ€sst sich fΓΌr verschiedene Themen verwenden (Objektorientierung, Web-Datenbank, KI, ...)
Neue Erfahrungen fΓΌr mich.ΒΆ
Python hat insbesondere in der Objektorientierung eine fundamental andere Herangehensweise als Java. Mein Blickwinkel auf Objektorientierung hat sich dadurch verΓ€ndert.
Das Python-Zen:
* Simple is better than complex
* flat is better than nested
* Readability counts
* If the implementation ist hard to explain, it's a bad idea
* If the implementation is easy to explain, it may be a good idea.
Jack Diderich - Stop Writing Classes (https://youtu.be/o9pEzgHorH0)
...oder: https://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html
GrundlagenΒΆ
Auf einen Blick:
- Es gibt keine Semikolons
;
- Variablen werden ohne Typen deklariert.
a = 3
- Anstelle von Klammern
{}
bzw.BEGIN END
starten BlΓΆcke mit einem : und werden eingerΓΌckt.for i in range(4): print(i)
- Um AusdrΓΌcke werden keine Klammern gesetzt.
if i > 3: i = i + 1
- Es gibt keine Arrays
import turtle
turtle.forward(100)
turtle.mainloop() # not needed in Thonny
import turtle
ben = turtle.Turtle()
ben.forward(100)
turtle.mainloop()
# Welche IDE?
- Thonny ( https://thonny.org/ ) vollkommen ausreichend.
- SchΓΌler nutzen oft selbst vscode oder pycharm
EinrΓΌckung und Schleifen:ΒΆ
import turtle
for _ in range(4):
for _ in range(4):
turtle.forward(50)
turtle.right(90)
turtle.penup()
turtle.forward(60)
turtle.pendown()
turtle.mainloop() # not needed: in Thonny
VerzweigungenΒΆ
from random import randint
for _ in range(1000):
x = randint(-100, 100)
y = randint(-100, 100)
turtle.penup()
turtle.speed(0)
turtle.setpos(x, y)
turtle.pendown()
if x < 0 == 0:
turtle.color("red")
turtle.dot(3)
elif x < 50:
turtle.color("grey")
turtle.dot(3)
else:
turtle.color("blue")
turtle.dot(3)
turtle.mainloop() # not needed: in Thonny
TextadventuresΒΆ
end = False
state = "start"
while not end:
if state == "start":
text = "Du stehst vor der Sporthochschule - Wo gehst du hin?"
choice = input(text)
if choice == "t":
state = "tagungsraum"
elif choice == "q":
end = True
elif state == "tagungsraum":
text = "Du bist im Tagungsraum"
choice = input(text)
DatentypenΒΆ
Python ist dynamisch typisiert:
x = 3
print(x)
print(type(x))
x = 4.0
print(type(x))
x = "4"
print(type(x))
3 <class 'int'> <class 'float'> <class 'str'>
x = input("Gib die erste Variable an")
y = int(input("Gib die zweite Variable an"))
print(x + y)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[3], line 3 1 x = input("Gib die erste Variable an") 2 y = int(input("Gib die zweite Variable an")) ----> 3 print(x + y) TypeError: can only concatenate str (not "int") to str
Datentypen und OperatorenΒΆ
System.out.println("Ausgabe: " + 1);
---> "Ausgabe:1"
Pascal/Delphi
writeln('Ausgabe: ' + 1);
---> Error
Python verhΓ€lt sich wie Pascal/Delphi:
print("1" + 1)
Numerische DatentypenΒΆ
- Es gibt nur
int
,float
undcomplex
- Es gibt keine
maxint
-Eigenschaft
lightyear_to_meter: int = 9460730472580800
milky_way_diameter = 100_000 * lightyear_to_meter
print(f"The milky way has a diameter of approximately {milky_way_diameter} meters")
The milky way has a diameter of approximately 946073047258080000000 meters
Aber float-Werte kΓΆnnen "ΓΌberlaufen" - Es wird dann allerdings ein Fehler geworfen.
a = 2.1
while a > 0:
a = a ** 2
print(a)
--------------------------------------------------------------------------- OverflowError Traceback (most recent call last) Cell In[5], line 3 1 a = 2.1 2 while a > 0: ----> 3 a = a ** 2 4 print(a) OverflowError: (34, 'Numerical result out of range')
Boolean DatentypenΒΆ
Man vergleicht booleans mit and
, or
und not
Beispiel:
if not a and not b:
do_something()
ListenΒΆ
- Python nutzt standardmΓ€Γig Listen im Gegensatz zu Delphi/Java (arrays)
- Listen kΓΆnnen unterschiedliche Datentypen enthalten.
- Listen kΓΆnnen dynamisch verlΓ€ngert werden.
a = [3, "Hallo Welt"]
for value in a:
print(value)
a.append("Noch ein Wert")
print(a)
Listen - Spezielle Operationen:ΒΆ
a = [3, "Hallo Welt"]
if (3 in a):
print("Ok")
a = [3, 4, 2]
if a:
print("Die Liste ist nicht leer")
LaufzeitenΒΆ
In der Python-Dokumentation kann man die Laufzeiten fΓΌr Listen-Operationen nachschlagen:
ArraysΒΆ
Theoretisch gibt es auch Arrays:
import array
a = array.array('i', [10, 20, 30])
print(a)
print(a[1])
List ComprehensionsΒΆ
## List Comprehensions
lst = [x for x in range(0, 10) if x % 2 == 0]
print(lst)
Γber Listen iterierenΒΆ
Die Java-Variante for (i=0;i<a.length;i++)
ist in Python nicht vorhanden, stattdessen:
lst = range(0, 10)
for value in lst:
print(value)
lst = range(0, 10)
for index, value in enumerate(lst):
print(index, value * value)
DictionariesΒΆ
telefonbuch = {"Stefan": 3213, "Klaus": 3212, "Stefan": 3021}
print(telefonbuch["Stefan"])
FunktionenΒΆ
def add(a, b, c = 0):
return a + b + c
print(add(3, 4))
* Funktionen kΓΆnnen Default-Parameter enthalten.
Funktionen als "First Class-Objects"ΒΆ
def add(a, b, c = 0):
return a + b + c
def action(func, a, b, c = 0):
return func(a, b, c)
print(action(add, 3, 4))
- Funktionen sind selbst auch Objekte und kΓΆnnen als solche ΓΌbergeben werden.
print(type(add))
a = add
a(3, 4)
ObjektorientierungΒΆ
Ein einfaches Beispiel fΓΌr eine Klasse.
class BankAccount:
def __init__(self):
self.balance = 0
andreasKonto = BankAccount()
print(andreasKonto.value)
__init__
wird aufgerufen, nachdem die die Instanz instanziiert wird.
Achtung: Typischer Fehler von Java-Umsteigern:ΒΆ
class BankAccount:
balance = 0
def __init__(self):
pass
andreasKonto = BankAccount()
martinKonto = BankAccount()
print(id(andreasKonto.balance), id(martinKonto.balance))
balance
ist hier eine Klassenvariable
Methoden:ΒΆ
class BankAccount:
def __init__(self):
self.balance = 0
self.interest_rate = 0.03
def deposit(self, balance):
self.balance += balance
def withdraw(self, balance):
self.balance -= balance
def add_interest(self):
self.balance += self.balance * self.interest_rate
andreasKonto = BankAccount()
andreasKonto.deposit(20)
andreasKonto.add_interest()
print(andreasKonto.balance)
- Klassen werden im CamelCase geschrieben, Methoden mit snake_case.
- Es fehlt noch Kapselung...
Kapselung - Teil 1ΒΆ
Python: Kapselung funktioniert anders als in Java und Delphi:
Mit Properties kann der Zugriff auf Attribute eingeschrΓ€nkt werden - Der Rest der Klasse muss dafΓΌr nicht verΓ€ndert werden!
class BankAccount:
def __init__(self, balance):
self._balance = balance
self.interest_rate = 0.03
@property
def balance(self):
return self._balance
@balance.setter
def balance(self, value):
self._balance = value
def deposit(self, balance):
self.balance += balance
def withdraw(self, balance):
self.balance -= balance
def add_interest(self):
self.balance += self.balance * self.interest_rate
andreasKonto = BankAccount(20)
andreasKonto.deposit(20)
andreasKonto.add_interest()
print(andreasKonto.balance)
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) Cell In[14], line 22 17 self.balance += self.balance * self.interest_rate 21 andreasKonto = BankAccount(20) ---> 22 andreasKonto.deposit(20) 23 andreasKonto.add_interest() 24 print(andreasKonto.balance) Cell In[14], line 11, in BankAccount.deposit(self, balance) 10 def deposit(self, balance): ---> 11 self.balance += balance AttributeError: property 'balance' of 'BankAccount' object has no setter
Vergleich mit Java/Delphi:ΒΆ
Python verfolgt ein anderes Paradigma beim Entwurf des Systems:
Idee Java/Delphi:
- Sichtbarkeiten werden im Voraus definiert
- Sichtbarkeiten sind Regeln, die auch von Programmiererinnen eingehalten werden mΓΌssen.
Idee Python:
- Es kann ein Prototyp erstellt werden, der ohne Sichtbarkeiten auskommt.
- Sichtbarkeiten kΓΆnnen im Nachhinein hinzugefΓΌgt werden.
- Sichtbarkeit sind Konventionen(!), auf die man sich geeinigt hat.
- Entwickler sind "erwachsene Leute".
_ und __ΒΆ
Technisch sind dies die Entsprechungen fΓΌr public/protected/private in Java:
self.attribute # public
self._attribute # protected
self.__attribute # private / name_mangling
Aber: In Python gilt nicht die Regel, dass alle Attribute private sein sollten. PEP8 sagt dazu:
"Not everyone likes name mangling. Try to balance the need to avoid accidental name clashes with potential use by advanced callers."
Meine HerangehensweiseΒΆ
Im Grundkurs hat sich folgende Herangehensweise bewΓ€hrt:
self._attribute
wird fΓΌr private Attribute verwendet,self.attribute
fΓΌr ΓΆffentliche Attribute.- Name Mangling habe ich bisher ausgeblendet.
- Properties habe ich exemplarisch verwendet, ansonsten einen eher Java-artigen Zugang zu Kapselung.
Vererbung InterfacesΒΆ
Es gibt keine Entsprechung fΓΌr (Java) Interfaces in Python.
Aber Mehrfach-Vererbung:
class Shape():
pass
class Printable():
def print(self):
pass
class Rectangle(Shape, Printable):
def __init__(self, x, y, width, height):
self.x, self.y, self.width, self.height = x, y, width, height
def print(self):
return(self.x, self.y, self.width, self.height)
r = Rectangle(3, 5, 4, 2)
print(r.print())
from abc import ABC, abstractmethod
class Shape(ABC):
pass
class Printable(ABC):
@abstractmethod
def print(self):
pass
class Rectangle(Shape, Printable):
def __init__(self, x, y, width, height):
self.x, self.y, self.width, self.height = x, y, width, height
def print(self):
return(self.x, self.y, self.width, self.height)
r = Rectangle(3, 5, 4, 2)
print(r.print())
Type HintsΒΆ
from typing import Type
class Client:
def __init__(self):
self.partner = None
class SimpleNetwork:
def __init__(self):
self.client1 : Type[Client] = Client()
self.client2 : Type[Client] = Client()
def get_client1(self) -> Type[Client]:
return self.client1
network = SimpleNetwork()
print(type(network.client1))
print(network.get_client1())
Mein Zugang zu ObjektorientierungΒΆ
Miniworldmaker - Objects firstΒΆ
So sieht Code in der E-Phase aus:
import miniworldmaker
board = miniworldmaker.Board()
r = miniworldmaker.Token((20, 20))
__
@r.register
def act(self):
self.x += 1
@r.register
def on_key_pressed(self, keys):
if 's' in keys:
self.y = self.y +1
board.run()
pygame 2.5.2 (SDL 2.28.2, Python 3.11.5) Hello from the pygame community. https://www.pygame.org/contribute.html init miniworldmaker app... Show new miniworldmaker v.2.18.3.0 Window Let's go can't check if run() is present (This can happen if you are using jupyter notebooks. Resuming)
An exception has occurred, use %tb to see the full traceback. SystemExit: 0
/home/andreas/code/python/jupyter/fobi-python/env/lib/python3.11/site-packages/IPython/core/interactiveshell.py:3534: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D. warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
...und so in der Q-Phase:
import miniworldmaker
import random
board = miniworldmaker.Board()
class MyToken(miniworldmaker.Token):
def on_setup(self):
self.x = random.randint(0,400)
self.y = random.randint(0, 400)
def act(self):
self.x+= 1
def on_key_pressed(self, keys):
self.y = self.y + 1
for _ in range(10):
MyToken()
board.run()
GUIΒΆ
Es gibt in Python viele GUIS: https://wiki.python.org/moin/GuiProgramming
- TKinter - Weit verbreitet
- guizero, pysimplegui, (appjar) - Gut geeignet im Bildungskontext.
GuiZeroΒΆ
from guizero import App, Text, PushButton, TextBox
def change_message():
label.value = f"Hello {input_box.value}"
app = App(height= 130, width = 200, title="Hello world")
input_box = TextBox(app, width = 200)
button = PushButton(app, text="Press me", command=change_message)
label = Text(app, text="")
app.display()
PySimpleGuiΒΆ
import PySimpleGUI as sg
layout = [[sg.Text("What's your name?")],
[sg.Input(key='-INPUT-')], # Define key '-INPUT'
[sg.Text(size=(40,1), key='-OUTPUT-')], # Define key '-OUTPUT'
[sg.Button('Ok'), sg.Button('Quit')]]
window = sg.Window('Window Title', layout)
while True:.
event, values = window.read()
if event == sg.WINDOW_CLOSED or event == 'Quit':
break
window['-OUTPUT-'].update(f"Hello {values['-INPUT-']}!")
window.close()
tkinterΒΆ
import tkinter as tk
window = tk.Tk()
def update():
global tk_label, tk_input
tk_label["text"] = f"Hallo {tk_input.get()}"
tk_input = tk.Entry(window)
tk_input.pack()
tk_label = tk.Label(window, text="")
tk_label.pack()
tk_button = tk.Button(window, text = "Absenden", command=update)
tk_button.pack()
tk.mainloop()
Unser VorgehenΒΆ
* Sehr projektorientiert
* Begleitende Moodle-Kurse mit Code-Runner und neuerdings H5P
Siehe auch...ΒΆ
- https://blu3r4y.github.io/python-for-java-developers/?print-pdf - Sehr umfangreife Beschreibung, wie sich Python und Java unterscheiden.
- https://cscircles.cemc.uwaterloo.ca/de/- Programmierkurs der University of Waterloo