Donnerstag, 29. November 2012

 

Einführung Objektorientiertes Programmieren

Sie finden hier ein paar Informationen zum objektorientierten Programmieren und den von uns verwendeten Begriffen:
Es folgt ein Beispiel:

Aufgabe: Finden Sie Klassen bzw. Objekte zu folgenden Begriffen: Leo, Tiger, Samurai, Elefant, Taigon, Benjamin Blümchen, Tier, Löwe
Lösung: Beim Programmieren muss man aus einer Aufgabenstellung immer wieder Objekte und Klassen identfizieren, die man zur Implementierung benötigt. Man kann z.B. alle Subjekte der Aufgabenstellung suchen und sich dazu fragen "ist das ein Objekt oder sind das viele Objekte?". In letzterem Fall hat man einen Kandidaten für eine Klasse. Sonst ist es ein Objekt. Nicht alle Objekte werden für das Programm benötigt.
Bei diesem Beispiel ist nur eine Liste von Tieren und Namen gegeben. Namen sind normalerweise Objekte, die verschiedenen Tiere sind natürlich Klassen.
Wir werden also die Klassen Tier, Tiger, Löwe und Elefant haben. Die anderen Begriffe sind konkrete Namen. Weiters können wir die "is-a" ("ist-ein") Beziehung Tiger is-a Tier, Löwe is-a Tier und Elefant is-a Tier ausmachen.
Damit ergibt sich folgendes Bild:


Kästchen mit unterstrichenen Namen stellen konkrete Objekte dar.
Die strichlierten Pfeile stellen die Instanzierung dar. Sie sind in Pfeilrichtung zu lesen: Leo ist-ein-konkreter Löwe (Leo is-instance-of Löwe) oder Samurai ist-ein-konkreter Tiger.
Die Pfeile mit Dreiecksspitzen und durchgehenden Linien stehen für die Vererbung (is-a, ist-ein), Beispielsweise Löwe ist-ein Tier (Löwe is-a Tier).

Die Klassen könnte man so implementieren (z.B. Scrapbook):
class Tier {
  String name;
  public String toString() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
}

class Löwe extends Tier {

}

class Elefant extends Tier {

}

class Tiger extends Tier {

}

Löwe leo = new Löwe();
leo.setName("Leo");
Elefant benjamin = new Elefant();
benjamin.setName("Benjamin Blümchen");
Tiger samurai = new Tiger();
samurai.setName("Samurai");
Tiger taigon = new Tiger();
taigon.setName("Taigon");
System.out.println(leo);
System.out.println(benjamin);
System.out.println(samurai);
System.out.println(taigon);

Die Ausgabe könnte so aussehen:
Leo
Benjamin Blümchen
Samurai
Taigon


In Python könnte man das Beispiel so implementieren:
class Tier:
    def __init__(self):
        self.name = ""
    def setName(self, name):
        self.name = name
    def __str__(self): # toString() in Java
        return self.name

class Loewe(Tier):
    pass

class Elefant(Tier):
    pass

class Tiger(Tier):
    pass

leo = Loewe()
leo.setName("Leo")
benjamin = Elefant()
benjamin.setName("Benjamin Blümchen")
samurai = Tiger()
samurai.setName("Samurai")
taigon = Tiger()
taigon.setName("Taigon");

print(leo)
print(benjamin)
print(samurai)
print(taigon)

Labels: , , ,


Montag, 12. November 2012

 

Python Objekte, Aufrufstack, Klassen (POS1)

Objekte

In Python sind alle Elemente Objekte. Folgendes Beispiel enthält ein paar solche Objekte:
def fun(x):       # auch ein Objekt!
    y = x * x
    return y

f2 = fun          # f1 ist eine Refernz auf fun

lst = [1, 2, fun] # Liste mit 3 Objekten
l2 = lst          # l2 ist eine Refernz auf obige Liste

erg = fun(2)
print(erg)
erg = f2(3)
print(erg)
print(f2 == fun)
print(l2 == lst)
print(lst)

Folgendes Bild zeigt den Speicher, wenn das Progarmm in der Zeile 3 angelangt ist, nach dem f2(3) (ist ja fun(3)) in der Zeile 12 Aufgerufen wurde.



Sie können den Ablauf unter folgendem Link testen: objects.py

Sie sehen auf der rechten Seite die Objekte, welche Python angelegt hat. Der linke Bereich ("Frames") zeigt den Speicher, den Python für die (globalen) Variablen anlegt sowie den Speicher für die aufgerufene Funktion. Für jede Funktion wird so ein Bereich (Frame) angelegt und beim beenden wieder zerstört.

Pfeile stellen Referenzen dar. Zum Beispiel stellt der Pfeil von lst zum Listenobjekt [1, 2, fun] dar. Auch l2 ist eine Referenz zu dieser Liste.
In dieser Liste gibt es eine weitere Referenz zur Funktion fun. Funktionsnamen sind also Referenzen zu "Funktions-Objekten" (die den Code der Funktion "enthalten").

Aufrufstack

Beim folgenden Beispiel können Sie sehen, wie Frames sich bei den Aufrufen der Funktion fact() stapeln und dann in Folge wieder zerstört werden:

def fact(n):
    if n > 1:
        return n * fact(n - 1)
    else:
        return 1

f = fact(5)
print(f)


Folgendes Bild zeigt die Frames, wenn das Programm die Zeile 5 erreicht (aber nicht ausgeführt) hat. Sie sehen einen Stapel von Frames. Ein Frame pro Aufruf. Diese Frames werden anschließend bei jedem return wieder zerstört. Man nennt diesen Stapel Aufrufstack:



Sie können den Ablauf unter folgendem Link testen: fact.py

Klassen

Bei Klassen handelt es sich um benutzerdefinierte Typen. D.h. es werden Typen ange- legt, für die benutzerdefinierte Methoden (also objektgebundene Funktionen) definiert werden können:
class Car:
    def __init__(self, cartype, kind, serNr):
        self.cartype = cartype
        # die Attribute type,
        self.kind = kind
        # kind und
        self.serNr = serNr
        # serNr sind in der Instanz
    def maxSpeed(self):
        if self.kind == "pickup": # Wenn Pickup, dann langsamer
            return 100.0
        else:
            return 130.0

passat1 = Car("VW/Passat", "regular_car", 11142)
jetta1 = Car("VW/Jetta", "small_car", 11143)
ram1 = Car("Dodge/Ram", "pickup", 22242)

fleet = [passat1, jetta1, ram1] # Fuhrpark
for car in fleet:
    print(car.cartype, car.maxSpeed(), "km/h")



Mittels der Anweisung class wird ein neuer Typ definiert. Dieser heißt in diesem Fall ‘Car’. Wir sehen, dass es sich bei der class Anweisung ebenfalls um eine Block - Anweisung handelt, da nach der Bezeichnung der Klasse (Car) der Doppelpunkt folgt und die danach folgenden Methoden eingerückt sind.
Die einzelnen Methoden werden wie Funktionen definiert. D.h. die Definition erfolgt durch das Schlüsselwort def. Als Unterschied gibt wird jedoch ein zusätzlicher Parameter an erster Stelle angeführt, der zur Ausführungszeit der Methode mit der Referenz des aktuellen Objektes vom Laufzeitsystem belegt wird.

Das folgende Bild zeigt, wie Python den Speicher für die Objekte und die Klasse angelegt hat.


Sie können das Programm hier ausführen car.py.

Die Ausgabe wäre wie folgt:
VW/Passat 130.0 km/h
VW/Jetta 130.0 km/h
Dodge/Ram 100.0 km/h


Durch Aufrufen der Klasse (durch Angabe des Klassennamens) und Übergabe der Initialisierungsparameter wird eine neue Instanz angelegt. Die übergebenen Parameter werden verwendet, um die spezielle Methdode __init__ nach dem Anlegen der Instanz aufzurufen. D.h. zuerst wird das neue Objekt angelegt und danach wird diese spezielle Methode aufgerufen. Dazu wird auch dieser Methode die Referenz auf das gerade angelegte Objekt mitgegeben (als Parameter self).
D.h. in der Methode __init__ werden die Attribute cartype, kind und serNr für das gerade erzeugte Objekt angelegt. D.h. ab diesem Zeitpunkt besitzt das Objekt diese Attribute. Die Methode maxSpeed kann danach ebenfalls auf diese Attribute zugreifen.

Attribute gehören also zu einem Objekt und können in den Methoden abgefragt und verändert werden. Anders als in anderen Programmiersprachen ist es jedoch so, dass der Zugriff auf diese Attribute nicht nur ausschließlich in den Methoden erfolgen kann. Diese Attribute können prinzipiell auch von außerhalb gelesen und verändert werden, wie man in obigem Beispiel in der Zeile 21 (print(...)) sehen kann.

Labels: , , ,


Montag, 5. November 2012

 

Testen und erweitern von ShoppingCart (POS1: 3BHIF)

Abgabename: 2012_3bhif_aufgabe4_Name_Vorname.tgz

Ziel dieser Aufgabe ist es, fremden Code zu testen, zu verstehen und zu erweitern. Dazu werden Sie ShoppingCart von zwei Mitschülern testen und um unten beschriebene Funktionalität erweitern. Schreiben Sie dazu UnitTests ShoppingCartTest (oder verwenden Sie ihre vorhandenen), welches die Funktionen von ShoppingCart testet.

Protokollieren Sie die Testläufe und beschreiben Sie die eventuell gefundenen Fehler in einer Textdatei errors.txt. Haben Sie Fehler entdeckt, so korrigieren Sie diese, sodass die Tests fehlerfrei laufen.

Sollten Ihre Tests Fehler enthalten, so korrigieren sie diese ebenfalls (solche Fehler werden Sie u.U. erst finden, wenn Sie das zweite Programm testen).

Erweitern Sie nun die Klasse MyCart so, dass sie folgendes Interface (zusätzlich zum Interface ShoppingCart) implementiert.
public interface ItemCount {

    /**
     * wieviele Element gibt's von anItem
     * 
     * @return Anzahl Elemente
     */
    public int itemCount(Item anItem) throws NoSuchItemException;
}
Das Ziel ist also eine Methode, welche die Anzahl eines bestimmten Items bestimmt.

Erweitern Sie Ihre Unit-Tests entsprechend.

Die Einteilung der Gruppen finden Sie in der Schule unter
/home/teachers/hp/public/3bhif/2012_3bhif_aufgabe4_gruppeneinteilung.pdf.

Sonntag, 4. November 2012

 

Testen und erweitern von text_analyzer.py (POS1: 2BHIF)

Abgabename: 2012_2bhif_aufgabe6_Name_Vorname.tgz

Ziel dieser Aufgabe ist es, fremden Code zu testen, zu verstehen und zu erweitern. Dazu werden Sie text_analyzer.py von zwei Mitschülern testen und um unten beschriebene Funktionalität erweitern. Schreiben Sie dazu ein Modul test_text_analyzer, welches die Funktionen vom Modul text_analyzer importiert und testet.

Protokollieren Sie die Testläufe und beschreiben Sie die eventuell gefundenen Fehler in einer Textdatei errors.txt. Haben Sie Fehler entdeckt, so korrigieren Sie diese, sodass die Tests fehlerfrei laufen.

Sollten Ihre Tests Fehler enthalten, so korrigieren sie diese ebenfalls (solche Fehler werden Sie u.U. erst finden, wenn Sie das zweite Programm testen).

Ergänzen Sie die Funktionalität von text_analyzer um die Funktion read_sentences(file), welche aus der geöffneten Datei file (d.h. die Datei muss vor dem Aufruf dieser Funktion geöffnet werden) Zeilen liest und in der selben Form wie die bereits bestehende Funktion input_sentences() liefert.

Ändern/Ergänzen Sie text_analyzer um ein main, welches prüft, ob Dateinamen auf der Kommandozeile angegeben wurden, diese Dateien der Reihe nach öffnet und das (End-)Ergebnis der Funktionen analyze_words(lst) und sort_letters(dic) ausgibt. Weiters sollen auch die Häufigkeiten der Worte, absteigend sortiert nach Häufigkeit (genau wie sort_letters(dic)) ausgegeben werden (braucht man eine neue Funktion?). Dabei soll die Ausgabe formatiert sein (also nicht nur die Listen bzw. Dictionaries ausgeben).
Werden keine Dateinamen angegeben, so ist wieder von der Konsole zu lesen.
Die Option -h gibt eine kurze Hilfe aus.

Die Einteilung der Gruppen finden Sie in der Schule unter
/home/teachers/hp/public/2bhif/2012_2bhif_aufgabe6_gruppeneinteilung.pdf.

Labels: , , ,


This page is powered by Blogger. Isn't yours?

Abonnieren Posts [Atom]