Commit 07f4b210 authored by Axel Dürkop's avatar Axel Dürkop
Browse files

Add oop chapters

parent 6e4613a4
+++
title= 'Klassen erstellen mit "class"'
date= 2019-04-02T12:50:13+01:00
draft= false
weight = 210
# Table of content (toc) is enabled by default. Set this parameter to true to disable it.
# Note: Toc is always disabled for chapter pages
disableToc = false
# If set, this will be used for the page's menu entry (instead of the `title` attribute)
menuTitle = ""
# The title of the page in menu will be prefixed by this HTML content
pre= ""
# The title of the page in menu will be postfixed by this HTML content
post = ""
# Set the page as a chapter, changing the way it's displayed
chapter= false
# Hide a menu entry by setting this to true
hidden = false
# Display name of this page modifier. If set, it will be displayed in the footer.
LastModifierDisplayName = "Axel Dürkop"
# Email of this page modifier. If set with LastModifierDisplayName, it will be displayed in the footer
LastModifierEmail = "axel.duerkop@tuhh.de"
+++
Um selbst Objekte in Python (und auch anderen objektorientierten Programmiersprachen) zu erstellen, ist eine *Klasse* zu definieren. Diese erfüllt die Funktion eines *Bauplans*, aus dem konkrete Objekte erstellt werden können - die *Instanzen*.
Um mit Klassen in der Processing-IDE bequem arbeiten zu können, wird folgendes Vorgehen empfohlen:
### Klassen definieren
Zunächst erstellen wir in der Processing-IDE (Python-Mode) das Grundgerüst eines Processing-Sketches.
```python
def setup():
pass
def draw():
pass
```
Den Sketch speichern wir unter dem Namen `Stimmungen` ab.
Die Processing-IDE unterstützt die Verwaltung von Programmteilen wie Klassen oder Modulen durch Tabs am Kopf des Editorbereichs. Für das Smiley-Beispiel erstellen wir also einen neuen Tab und vergeben den Namen `Smiley`. Processing macht daraus den Dateinamen `Smiley.py`.
![Erstellen eines neuen Tabs in Processing](/images/neuer-tab.png)
Im Dateisystem unseres Rechners wird das Projekt nun wie folgt abgebildet:
![Aufbau des Sketches im Dateisystem](/images/oop-tree.png)
`Stimmungen.pyde` ist die Hauptdatei des Sketches, `Smiley.py` die Datei für unsere Klasse. Jetzt können wir beginnen, die ersten Zeilen für die Klasse `Smiley` zu schreiben.
```python
class Smiley:
pass
```
Mit dem Schlüsselwort `class` gefolgt von einem bezeichnenden Substantiv beginnt die Definition. `pass` ist an dieser Stelle wieder nur ein Platzhalter für Code, der später folgt.
Unsere Klasse soll eine erste Eigenschaft in Form einer Funktion bekommen. Sind Funktionen Teil einer Klasse, spricht man von einer *Methode*.
```python
class Smiley:
def say_something(self, something):
print(something)
```
Methoden werden genauso wie Funktionen definiert - einziger Unterschied an dieser Stelle: Als Argument muss immer `self` übergeben werden. `self` steht für eine Instanz der Klasse `Smiley`. Dieses Konzept wird in Kürze deutlicher, wenn wir konkrete Objekte bzw. Instanzen aus der Klasse erstellen.
\ No newline at end of file
+++
title= "Mehr Eigenschaften"
date= 2019-04-02T12:50:13+01:00
draft= false
weight = 230
# Table of content (toc) is enabled by default. Set this parameter to true to disable it.
# Note: Toc is always disabled for chapter pages
disableToc = false
# If set, this will be used for the page's menu entry (instead of the `title` attribute)
menuTitle = ""
# The title of the page in menu will be prefixed by this HTML content
pre= ""
# The title of the page in menu will be postfixed by this HTML content
post = ""
# Set the page as a chapter, changing the way it's displayed
chapter= false
# Hide a menu entry by setting this to true
hidden = false
# Display name of this page modifier. If set, it will be displayed in the footer.
LastModifierDisplayName = "Axel Dürkop"
# Email of this page modifier. If set with LastModifierDisplayName, it will be displayed in the footer
LastModifierEmail = "axel.duerkop@tuhh.de"
+++
Nachdem wir die grundlegenden Konzepte von Klassen hergeleitet haben, wollen wir dem Smiley nun mehr Gestalt geben. Dafür erweitern wir zunächst die Klassendefinition.
```python
# -*- coding: utf-8 -*-
class Smiley:
def say_something(self, something):
print(something)
def paint(self, x_pos, y_pos, size_xy):
""" Malt einen Smiley auf Basis der übergebenen
Argumente. Positionen von Augen und Mund werden
aus den Parametern errechnet.
"""
ellipseMode(CENTER)
# Körper
ellipse(x_pos, y_pos, size_xy, size_xy)
# Füllfarbe setzen
fill(0)
# Auge links
ellipse(x_pos - size_xy * .2, y_pos - size_xy * .12, size_xy * .2, size_xy * .2)
# Auge rechts
ellipse(x_pos + size_xy * .2, y_pos - size_xy * .12, size_xy * .2, size_xy * .2)
# Mund
noFill()
arc(x_pos, y_pos, size_xy * .75, size_xy * .75, radians(25), radians(155));
# Füllfarbe zurücksetzen
fill(255)
```
Keine Angst vor dem bisschen Mathematik, es sieht schlimmer aus, als es ist. Im Grunde handelt es sich um Prozentrechung, um ausgehend von `size_xy` die Positionen von Augen und Mund korrekt berechnen zu können.
Im Hauptsketch können wir nun richtige Smileys auf die Leinwand zeichnen.
```python
from Smiley import Smiley
smiley1 = Smiley()
smiley2 = Smiley()
def setup():
global smiley1, smiley2
size(200,200)
smiley1.paint(50, 50, 20)
smiley2.paint(150, 150, 70)
def draw():
pass
```
Das Ergebnis ist schon ganz passabel.
![Zwei Smileys](/images/zwei-smileys.png)
Im nächsten Schritt sollten wir uns darum kümmern, dem Smiley ein wenig mehr Farbe zu geben. Dabei soll es möglich sein, jedes Objekt unterschiedlich einzufärben. Die Farbgebung soll schon in dem Moment der Objekterzeugung erfolgen:
```python
# Änderung im Hauptprogramm
smiley1 = Smiley('#FFFF00') # gelb
smiley2 = Smiley('#0077FF') # blau
```
Damit das funktioniert, muss die Klassendefinition angepasst werden.
```python
# -*- coding: utf-8 -*-
class Smiley:
def __init__(self, col):
self.col = col
def say_something(self, something):
print(something)
def paint(self, x_pos, y_pos, size_xy):
""" Malt einen Smiley auf Basis der übergebenen
Argumente. Positionen von Augen und Mund werden
aus den Parametern errechnet.
"""
ellipseMode(CENTER)
## Füllfarbe setzen
fill(self.col)
# Körper
ellipse(x_pos, y_pos, size_xy, size_xy)
# Füllfarbe temporär ändern
fill(0)
# Auge links
ellipse(x_pos - size_xy * .2, y_pos - size_xy * .12, size_xy * .2, size_xy * .2)
# Auge rechts
ellipse(x_pos + size_xy * .2, y_pos - size_xy * .12, size_xy * .2, size_xy * .2)
# Mund
noFill()
arc(x_pos, y_pos, size_xy * .75, size_xy * .75, radians(25), radians(155));
# Füllfarbe zurücksetzen
fill(self.col)
```
Neu dazu gekommen ist die Definition einer speziellen Methode der Klasse, dem **Konstruktor**. Diese Methode wird **in dem Moment aufgerufen, in dem das Objekt erzeugt wird.** Sollen dabei Argumente berücksichtigt werden, müssen diese bei der *Instanziierung* des Objekts übergeben werden.
Es besteht also folgender Zusammenhang zwischen Instanziierung eines Objekts der Klasse im Hauptprogramm und dem Konstruktor:
```python
# Hauptprogramm
smiley1 = Smiley('#FFFF00') # gelb
smiley2 = Smiley('#0077FF') # blau
# Klassendefinition
class Smiley:
def __init__(self, col):
self.col = col
```
Der Konstruktor speichert die übergebenen Argumente in einer *Instanzvariablen*, hier `col`. Durch die Bindung an `self` wird klar, dass die Farbe nicht zur Klasse, sondern zu jedem einzelnen Objekt gehört. Der Konstruktor wird immer mit `__init__()` definiert.
Im restlichen Code wird nun die Füllfarbe entsprechend gesetzt.
![Bunte Smileys](/images/oop-bunte-smileys.png)
### Zwischenfazit
Die bisherigen Kapitel haben erste Ansätze objektorientierter Programmierung vermittelt. Dabei sind folgende Aspekte angesprochen worden:
* Definition eigener Klassen als Baupläne für Objekte
* Erstellen von Objekten als Instanzen einer Klasse
* Definition von Funktionen innerhalb der Klassendefinition. Diese nennt man *Methoden*.
* Verwendung von Instanzvariablen
* Einsatz und Bedeutung des Schlüsselwortes `self` im Rahmen der Klassendefinition.
\ No newline at end of file
+++
title= "Objekte erstellen"
date= 2019-04-02T12:50:13+01:00
draft= false
weight = 220
# Table of content (toc) is enabled by default. Set this parameter to true to disable it.
# Note: Toc is always disabled for chapter pages
disableToc = false
# If set, this will be used for the page's menu entry (instead of the `title` attribute)
menuTitle = ""
# The title of the page in menu will be prefixed by this HTML content
pre= ""
# The title of the page in menu will be postfixed by this HTML content
post = ""
# Set the page as a chapter, changing the way it's displayed
chapter= false
# Hide a menu entry by setting this to true
hidden = false
# Display name of this page modifier. If set, it will be displayed in the footer.
LastModifierDisplayName = "Axel Dürkop"
# Email of this page modifier. If set with LastModifierDisplayName, it will be displayed in the footer
LastModifierEmail = "axel.duerkop@tuhh.de"
+++
Da die Klassendefinition in einer eigenen Datei liegt, hat das Hauptprogramm keine Kenntnis von ihr. Daher müssen wir die Klassendefinition im Hauptprogramm *importieren*.
```python
from Smiley import Smiley
def setup():
pass
def draw():
pass
```
Die erste Zeile lässt sich so lesen: Aus der Datei `Smiley.py` importiere die darin enthaltene Klasse `Smiley`. Beachte, dass die Dateiendung nicht angegeben wird.
Nun haben wir Zugriff auf die Klasse und können ein erstes Objekt erstellen.
```python
from Smiley import Smiley
smiley1 = Smiley()
def setup():
pass
def draw():
pass
```
In der neuen Zeile wird der Variablen `smiley1` eine Instanz der Klasse `Smiley` zugewiesen. Das heißt konkret, dass unsere Klassendefinition als Bauanleitung genommen wurde, um daraus ein konkretes Objekt zu erstellen. Weil das so einfach geht, lassen wir uns gleich noch einen zweiten Smiley bauen.
```python
from Smiley import Smiley
smiley1 = Smiley()
smiley2 = Smiley()
def setup():
pass
def draw():
pass
```
Wichtig an dieser Stelle ist das Verständnis dafür, dass Python zwei völlig eigenständige Bereiche im Speicher für `smiley1` und `smiley2` verwaltet. Die einzige Gemeinsamkeit der beiden Objekte ist ihre Herkunft, die Klasse `Smiley`.
Unser Smiley ist ja grundsätzlich mit einem minimalen *Können* ausgestattet: Er kann was sagen. Das können wir in unserem Code wie folgt abbilden:
![Stimmungen der Smileys](/images/oop-aussagen-smileys.png)
In der Zeile
```python
smiley1.say_something("Smiley1: Mir geht's blendend!")
```
rufen wir eine Methode des Objekts `smiley1` auf und übergeben ein Argument. Python sucht dann nach der Klasse, aus der das Objekt entstanden ist und darin nach der Methode. Schauen wir uns nochmal den entsprechenden Abschnitt in der Klassendefinition an,
```python
class Smiley:
def say_something(self, something):
print(something)
```
fällt unser Blick erneut auf das Schlüsselwort `self`. Es ist dafür zuständig, dass beim Aufruf der Methode nicht das *Klassenobjekt*, sondern das *Instanzobjekt* angesprochen wird. `self` bezieht sich also immer auf ein konkretes Objekt, auf eine Instanz der Klasse, nicht auf die Klasse als Bauplan. Dadurch ist es möglich, unterschiedliche Parameter wie in unserem Beispiel zu übergeben und die Smiley individuelle Aussagen machen zu lassen.
\ No newline at end of file
+++
title= "Objektorientierte Programmierung (OOP)"
date= 2019-04-02T12:50:13+01:00
draft= false
weight = 200
# Table of content (toc) is enabled by default. Set this parameter to true to disable it.
# Note: Toc is always disabled for chapter pages
disableToc = false
# If set, this will be used for the page's menu entry (instead of the `title` attribute)
menuTitle = ""
# The title of the page in menu will be prefixed by this HTML content
pre= ""
# The title of the page in menu will be postfixed by this HTML content
post = ""
# Set the page as a chapter, changing the way it's displayed
chapter= false
# Hide a menu entry by setting this to true
hidden = false
# Display name of this page modifier. If set, it will be displayed in the footer.
LastModifierDisplayName = "Axel Dürkop"
# Email of this page modifier. If set with LastModifierDisplayName, it will be displayed in the footer
LastModifierEmail = "axel.duerkop@tuhh.de"
+++
Objektorientierte Programmierung (OOP) ist in vielen Bereichen der Programmierung zum vorherrschenden Konzept geworden. Um es zu verstehen, sollte man zunächst die Bedeutung des Begriffs *Objektorientierte Programmierung* einmal genauer unter die Lupe nehmen. Wir, die Subjekte, nehmen die Welt außerhalb von uns als *gegenständlich* wahr. Man könnte auch sagen, wir sehen, riechen, hören, schmecken und ertasten die Welt in ihrer Gegenständlichkeit, in ihrer Objekthaftigkeit. Dabei sind wir in der Lage, *Eigenschaften* dieser Objekte anzugeben. Wir können sagen, wie etwas *ist* und was etwas *kann*. Im Kontext von Processing wählen wir ein erstes Beispiel, das wir später in Code umsetzen werden:
### Eigenschaften eines Smileys
* Er ist farbig.
* Er kann lächeln oder traurig sein.
Bemerkenswert ist hier die Qualität der Eigenschaften: Die erste drückt eher einen *Zustand* aus, die zweite ein *Können*, eine Funktion. Dieser Unterschied wird in der OOP auch im Code abgebildet.
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment