Mittwoch, 12. November 2014

 

Mini-Vergleich von Programmiersprachen

Dieser Artikel vergleicht ein paar Programmiersprachen (die in der Abteilung Informatik der HTL Wiener Neustadt unterrichtet werden) und dient nur zur Demonstration der "Optik" dieser Sprachen.

Als Beispiel kommt "99 bottles of beer" zum Einsatz. Die Programme stammen von http://99-bottles-of-beer.net/ und dienen eigentlich nur als Beispiele, um die Code-Struktur kleinerer Programme zu sehen.

Python

Python unterstützt mehrere Programmierparadigmen. So werden objektorientierte, aspektorientierte und funktionale Programmierung unterstützt. Wie andere dynamische Sprachen wird Python oft als Skriptsprache genutzt.
"""
99 bottles of beer in Python
"""
for quant in range(99, 0, -1):
    if quant > 1:
        print(quant, "bottles of beer on the wall,", quant, "bottles of beer.")
        if quant > 2:
            suffix = str(quant - 1) + " bottles of beer on the wall."
        else:
            suffix = "1 bottle of beer on the wall."
    elif quant == 1:
        print("1 bottle of beer on the wall, 1 bottle of beer.")
        suffix = "no more beer on the wall!"
    print("Take one down, pass it around,", suffix)
    print("--")
Hier die Python Lösung zum Ausführen

Java

Java ist eine objektorientierte Programmiersprache und eine eingetragene Marke des Unternehmens Sun Microsystems (seit 2010 Oracle). Die Programmiersprache ist ein Bestandteil der Java-Technologie – diese besteht grundsätzlich aus dem Java-Entwicklungswerkzeug (JDK) zum Erstellen von Java-Programmen und der Java-Laufzeitumgebung (JRE) zu deren Ausführung. Die Laufzeitumgebung besteht selbst aus der virtuellen Maschine (JVM) sowie den mitgelieferten Bibliotheken der Java-Laufzeitumgebung.
/*
 * 99 bottles of beer in Java
 */
class bottles {
    public static void main(String args[]) {
        String s = "s";
        for (int beers=99; beers>-1;) {
            System.out.print(beers + " bottle" + s + " of beer on the wall, ");
            System.out.println(beers + " bottle" + s + " of beer, ");
            if (beers==0) {
                System.out.print("Go to the store, buy some more, ");
                System.out.println("99 bottles of beer on the wall.\n");
                System.exit(0);
            } else
                System.out.print("Take one down, pass it around, ");
            s = (--beers == 1)?"":"s";
            System.out.println(beers + " bottle" + s + " of beer on the wall.\n");
        }
    }
}

C

C ist eine imperative Programmiersprache, die der Informatiker Dennis Ritchie in den frühen 1970er Jahren an den Bell Laboratories für die Systemprogrammierung des Betriebssystems Unix entwickelte. Seitdem ist sie auf vielen Computersystemen verbreitet. Die Anwendungsbereiche von C sind sehr verschieden. Sie wird zur System- und Anwendungsprogrammierung eingesetzt. Die grundlegenden Programme aller Unix-Systeme und die Systemkerne vieler Betriebssysteme sind in C programmiert. Zahlreiche Sprachen, wie C++, Objective-C, C#, Java, PHP, Vala oder Perl orientieren sich an der Syntax und anderen Eigenschaften von C.
/* 
 * 99 bottles of beer in C
 */
#define MAXBEER (99)

void chug(int beers);

main()
{
    register beers;

    for(beers = MAXBEER; beers; chug(beers--))
        puts("");

    puts("\nTime to buy more beer!\n");

    exit(0);
}

void chug(register beers)
{
    char howmany[8], *s;

    s = beers != 1 ? "s" : "";
    printf("%d bottle%s of beer on the wall,\n", beers, s);
    printf("%d bottle%s of beeeeer . . . ,\n", beers, s);
    printf("Take one down, pass it around,\n");

    if(--beers) sprintf(howmany, "%d", beers); else strcpy(howmany, "No more");
    s = beers != 1 ? "s" : "";
    printf("%s bottle%s of beer on the wall.\n", howmany, s);
}

C++

C++ ist eine von der ISO genormte Programmiersprache. Sie wurde ab 1979 von Bjarne Stroustrup bei AT&T als Erweiterung der Programmiersprache C entwickelt. C++ ermöglicht sowohl die effiziente und maschinennahe Programmierung als auch eine Programmierung auf hohem Abstraktionsniveau.

C++ unterstützt mehrere Programmierparadigmen:
/*
 * 99 bottles of beer in C++
 */
#include <iostream>
using namespace std;

int main()
{
    int bottles = 99;
    while ( bottles > 0 )
    {
        cout << bottles << " bottle(s) of beer on the wall," << endl;
        cout << bottles << " bottle(s) of beer." << endl;
        cout << "Take one down, pass it around," << endl;
        cout << --bottles << " bottle(s) of beer on the wall." << endl;
    }
    return 0;
}

C#

C# (lies englisch c sharp, englische Aussprache [ˌsiːˈʃɑːp]) ist eine vom Softwarehersteller Microsoft im Rahmen seiner .NET-Strategie entwickelte Programmiersprache. C# ist bei ECMA und ISO als Standard registriert.

C# unterstützt mehrere Programmierparadigmen:
/*
 * 99 bottles of beer in C#
 */
using System;
using System.Linq;
using System.Text;

namespace NinetyNineBottles
{
  class Beer
  {
    static void Main(string[] args)
    {
        StringBuilder beerLyric = new StringBuilder();
        string nl = System.Environment.NewLine;

        var beers =
            (from n in Enumerable.Range(0, 100)
             select new { 
               Say =  n == 0 ? "No more bottles" : 
                     (n == 1 ? "1 bottle" : n.ToString() + " bottles"),
               Next = n == 1 ? "no more bottles" : 
                     (n == 0 ? "99 bottles" : 
                     (n == 2 ? "1 bottle" : n.ToString() + " bottles")),
               Action = n == 0 ? "Go to the store and buy some more" : 
                                 "Take one down and pass it around"
             }).Reverse();

        foreach (var beer in beers)
        {
            beerLyric.AppendFormat("{0} of beer on the wall, {1} of beer.{2}",
                                    beer.Say, beer.Say.ToLower(), nl);
            beerLyric.AppendFormat("{0}, {1} of beer on the wall.{2}", 
                                    beer.Action, beer.Next, nl);
            beerLyric.AppendLine();
        }
        Console.WriteLine(beerLyric.ToString());
        Console.ReadLine();
    }
  }
}

Labels: , , , ,


Montag, 18. November 2013

 

Musterlösung Römische Zahlen umwandeln (POS1: 2BHIF)

Mögliche Lösung zu Römische Zahlen umwandeln (POS1: 2BHIF).

Die Klasse könnte folgendermaßen programmiert werden. Das Dictionary enthält die möglichen "Ziffern" (unter Hochkomma, da bestimmte Ziffernkombinationen, wie zum Beispiel "IX", als eine Ziffer gelten). Zur Umrechnung müssen die Werte absteigend sortiert werden, damit die richtige "Ziffer" (z.B. "IX" für 9) verwendet wird.

Bei der Umrechnung in römische Zahlen wird der Reihe nach von der größten zur kleinsten "Ziffer" (daher absteigend sortiert) probiert, ob der Wert enthalten ist. Ist das der Fall, dann wird die "Ziffer" an den String angehängt und der entsprechende Wert von der Zahl abgezogen. Zum Beispiel 1999

1999 M
999 IM
0 ferig
oder 392
392 C
292 C
192 C
92 XC
2 I
1 I
0 fertig

Bei der umgekehrten Umrechnung wird der Reihe nach probiert, ob am Beginn der römischen Zahl eine bestimmte "Ziffer" vorkommt. Ist dies der Fall, so wird der entsprechende Wert zum Ergebnis dazugezählt. Mit einem Zähler wird geprüft, dass keine Ziffer mehr als drei mal vorkommt. Zum Beispiel CCCXCII

CCCXCII 100 (C)
CCXCII 200 (C)
CXCII 300 (C)
XCII 390 (XC)
II 391 (I)
I 392 (I)

Zum Testen wird einfach eine Liste von Zahlen verwendet, die in römische Zahlen und wieder zurück gerechnet werden. Ungültige Zahlen liefern eine Exception, die bei einem entsprechenden Testfall kommen muss:

    # test value error
    try:
        ra = RomanNumber("VIIII")
        assert(False)
    except ValueError:
        pass

Die gesamte Klasse könnte also so aussehen:

#!/usr/bin/env python3
"""
 File:    RomanNumber.py
 Desc:    class for roman numbers
 Created: 2013-11-18, Harald R. Haberstroh
"""
class RomanNumber:
    """Roman numbers.
    Internal representation is always the integer value.
    This implementation stores both values (integer and roman).
    """
    digits = { "I":1, "V":5, "X":10, "L":50, "C":100, "D":500, "M":1000,
               "IV":4, "IX":9, "XL":40, "XC":90, "CD":400, "CM":900}
    keys = list(digits.items())
    keys.sort(key=lambda x: -x[1])

    def __init__(self, value):
        """Initialize with value.
        If type of value is int, than this is the integer value.
        If type of value is str, than this is a roman number, which has
        to be converted into the internal int-value"""
        if type(value) is str:
            self.roman = value
            self.intval = self.__toInt(value)
        else:
            self.intval = value
            self.roman = self.__toRoman(value)

    def toRoman(self):
        """returns string with roman representation"""
        return self.roman

    def toInt(self):
        """returns integer value of roman number"""
        return self.intval

    def add(self, other):
        """add the value of other (RomanNumber) to own (self) value and
        return a new RomanNumber object."""
        return RomanNumber(self.intval + other.toInt())

    def sub(self, other):
        """subtract the value of other (RomanNumber) from own (self) value and
        return a new RomanNumber object."""
        return RomanNumber(self.intval - other.toInt())

    def mul(self, other):
        """multiply the value of other (RomanNumber) with own (self) value and
        return a new RomanNumber object."""
        return RomanNumber(self.intval * other.toInt())

    def div(self, other):
        """divide (integer division) own value by the value of other value and
        return a new RomanNumber object."""
        return RomanNumber(self.intval // other.toInt())

    def __str__(self):
        """returns the same value as toRoman(self)"""
        return "%s (%d)" % (self.roman, self.intval)

    def __toRoman(self, intval):
        romval = ""
        for digit, val in self.keys:
            while intval >= val:
                romval += digit
                intval -= val
        return romval

    def __toInt(self, romval):
        roman = romval.upper()
        intval = 0
        for digit, val in self.keys:
            cntDigit = 0 # count same group
            while roman.startswith(digit):
                intval += val
                roman = roman[len(digit):]
                cntDigit += 1
                if cntDigit >= 4:
                    raise ValueError()
        return intval

if __name__ == '__main__':
    zahlen = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 21, 32, 43, 48, 49, 54, 65, 76, 87, 98,
          99, 100, 201, 302, 403, 491, 499, 504, 605, 706, 807, 908, 999, 1001,
          1279, 1331, 1496, 1883, 1949, 1967, 1990, 1999, 2006, 2013]

    for f in zahlen:
        rn = RomanNumber(f)
#        print('%4d: %20s - %4d' % (f, rn.toRoman(), rn.toInt()))
        assert(f == rn.toInt())

    for i in range(len(zahlen) // 2):
        ra = RomanNumber(zahlen[i])
        rb = RomanNumber(zahlen[-i])
        rc = ra.add(rb)
        print(ra, "+", rb, "=", rc)
        assert(zahlen[i] + zahlen[-i] == rc.toInt())
        rc = rb.sub(ra)
        print(rb, "-", ra, "=", rc)
        assert(zahlen[-i] - zahlen[i] == rc.toInt())
    for i in range(len(zahlen) // 8):
        ra = RomanNumber(zahlen[i])
        rb = RomanNumber(zahlen[len(zahlen) // 2 - i])
        rc = ra.mul(rb)
        print(ra, "*", rb, "=", rc)
        assert(zahlen[i] * zahlen[len(zahlen) // 2 - i] == rc.toInt())

    # test value error
    try:
        ra = RomanNumber("VIIII")
        assert(False)
    except ValueError:
        pass
    print("all tests passed")

Beim romancalc.py wird jeder Schritt mit einem try - except - Block umgeben, um die Fehler- und Sonderfälle zu behandeln.

Eine Spezialität ist der Aufruf des entsprechenden Operators. Hier wird ein Dictionary mit den möglichen Operationen verwendet, wobei der Aufruf als Funktion und nicht als Methode stattfindet (der erste Parameter self enthält ja das Objekt, welches dann explizit mit übergeben wird).

Das gesamte Modul könnte wie folgt aussehen:

#!/usr/bin/env python3
"""
 File:    romancalc.py
 Desc:    simple caluculator for roman numbers, using RomanNumber
 Created: 2013-11-18, Harald R. Haberstroh
"""
from RomanNumber import RomanNumber
import sys

operators = { "+":RomanNumber.add, "-":RomanNumber.sub,
              "*":RomanNumber.mul, "/":RomanNumber.div }
while True:
    try:
        line = input(">>> ")
    except EOFError:
        break
    try:
        a, op, b = line.split()
    except ValueError:
        print("syntax error", file=sys.stderr)
        continue
    if a.isdigit():
        a = int(a)
    if b.isdigit():
        b = int(b)
    try:
        ra = RomanNumber(a)
        rb = RomanNumber(b)
    except ValueError:
        print("invalid roman number", file=sys.stderr)
        continue
    try:
        rc = operators[op](ra, rb)
        print(ra, op, rb, "=", rc)
    except KeyError:
        print("invalid operator '%s'" % (op), file=sys.stderr)

Labels: , , ,


 

Römische Zahlen umwandeln (POS1: 2BHIF)

Abgabename: 2013_2bhif_aufgabe6_name_vorname.tgz

Römische Zahlen

Schreiben Sie eine Klasse RomanNumber, welche es erlaubt, mit römischen Zahlen zu rechnen bzw. römische Zahlen in ganze Zahlen und umgekehrt umzurechnen. Schreiben Sie dazu Methoden zum Umrechnen von ganzen Zahlen (1 bis 3000) in Römische Zahlen und umgekehrt. Die römischen Ziffern haben folgende Bedeutung:

I ...    1
V ...    5
X ...   10
L ...   50
C ...  100
D ...  500
M ... 1000
Beachten Sie, dass nur jeweils drei gleiche Ziffern hintereinander geschrieben werden. Stattdessen wird die nächst größere Einheit benutzt und eine Einheit abgezogen (XC = 90, XCIX = 99, IX = 9, VIII = 8).
class RomanNumber:
    """Roman numbers.
    Internal representation is always the integer value.
    """

    def __init__(self, value):
        """Initialize with value.
        If type of value is int, than this is the integer value.
        If type of value is str, than this is a roman number, which has
        to be converted into the internal int-value"""
        pass

    def toRoman(self):
        """returns string with roman representation"""
        pass

    def toInt(self):
        """returns integer value of roman number"""
        pass

    def add(self, other):
        """add the value of other (RomanNumber) to own (self) value and
        return a new RomanNumber object."""
        pass

    def sub(self, other):
        """subtract the value of other (RomanNumber) from own (self) value and
        return a new RomanNumber object."""
        pass

    def mul(self, other):
        """multiply the value of other (RomanNumber) with own (self) value and
        return a new RomanNumber object."""
        pass

    def __str__(self):
        """returns the value like 'XXII (23)'"""
        pass

Ergänzen Sie dieses Gerüst zu einer funktionierenden Klasse und schreiben Sie ein Testprogramm mit fix programmierten Testfällen.

Schreiben Sie weiters ein zweites Modul, welches die Klasse RomanNumber importiert und jeweils eine Zeile der Art

zahl op zahl
einliest, die Operation op (+, - oder *) ausführt und das Ergebnis ganzzahlig und als Römische Zahl ausgibt. zahl ist jeweils eine ganze Zahl oder eine römische Zahl.

Beispielaufrufe:

~/work/tmp > python romancalc.py
>>> 24 + 27
LI (51)
>>> LI - 24
XXVII (27)
>>> LI - XXIV
XXVII (27)
>>>
~/work/tmp > 
Zum Schluss wurde EOF eingegeben (Strg-D), die Eingaben sind fett gedruckt.

Informationen finden Sie unter:

Labels: , , ,


Mittwoch, 13. November 2013

 

Einführung Objektorientiertes Programmieren (POS1: 2BHIF)

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).



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)

Erstellen Sie für die folgenden Beispiele passende Klassen- bzw. Objektdiagramme (UML) und implementieren Sie die in Python!

Beispiel 1
Mensch, Lebewesen, Mohrle, Mann, Paul, Paula, Helmut, Rex, Frau, Tier, Susi, Biene Maya, Pinocchio

Beispiel 2

Verkehrsmittel, Schiff, Auto, Porsche von Herrn Mayer, Dreirad, Fahrrad, Dreirad von Maxi, Sportwagen, Käfer von Paula, Düsenjet von Daniel

Labels: ,


Montag, 11. November 2013

 

Python class (POS1: 2BHIF)

Erzeugen Sie eine einfache Klasse für Sportler. Sportler haben in unserem Beispiel einen Namen, ein Geburtsdatum und eine Liste von Zeiten (z.B. wie schnell ist der die letzten 100m-Läufe gelaufen).

Nennen Sie die Klasse Sportler

class Sportler:
   pass

Definieren Sie eine Methode zur Ermittlung der besten (Lauf-)Zeit (minimale Zeit aus der Liste von Zeiten).

Legen Sie mindestens 3 Sportler an und lassen Sie deren Namen, das Geburtsdatum und Bestzeit ausgeben.

Labels: , ,


Montag, 4. November 2013

 

Python Objekte, Wiederholung Aufrufstack (POS1: 2BHIF)

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 angelegt, 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: ,


 

Übungen (POS1: 2BHIF)

Sie finden an dieser Stelle eine Reihe von Fragen und Aufgaben, die Sie jetzt beantworten bzw. lösen können sollten. Aussagenlogik ist bei diesen Fragen ausgeklammert.

Theorie
  1. Was ist eine Variable?
  2. Welche Grunddatentypen kennen Sie?
  3. Was ist ein Liste?
  4. Geben Sie einen Algorithmus (ohne Programmdetails) an, um alle Elemente einer Liste zu ermitteln, die ein bestimmtes Kriterium (z.B. ist größer als ein bestimmter Wert) erfüllen.
  5. Geben Sie einen Algorithmus (ohne Programmdetails) an, um alle Elemente eine Liste von Listen zu ermitteln, die ein bestimmtes Kriterium erfüllen.
  6. Geben Sie einen Algorithmus (ohne Programmdetails) an, um das Maximum aller Werte einer Liste zu ermitteln.
  7. Geben Sie einen Algorithmus (ohne Programmdetails) an, um das Minimum aller Werte einer Liste zu ermitteln.
  8. Geben Sie einen Algorithmus (ohne Programmdetails) an, um das Maximum aller Werte einer Liste von Listen zu ermitteln.
  9. Geben Sie einen Algorithmus (ohne Programmdetails) an, um das Minimum aller Werte einer Liste von Listen zu ermitteln.
  10. Was ist eine Funktion? Geben Sie ein Beispiel in Python inklusive der Verwendung der Funktion.
  11. Wozu benötigt man Kommentare?
  12. Wozu benötigt man Programmierrichtlinien?
  13. Was ist ein Dictionary in Python?
  14. Was bedeutet der Begriff "Sequenz" in Python? Geben Sie einige Beispiele.
  15. Was muss grundsätzlich (ohne Programmdetails) gemacht werden, um von einer Datei zu lesen?
  16. Was muss grundsätzlich (ohne Programmdetails) gemacht werden, um in eine Datei zu schreiben?
  17. Geben Sie einen Algorithmus (ohne Programmdetails) an, um alle Zeilen einer Textdatei zu ermitteln, die ein bestimmtes Kriterium (z.B. enthält einen bestimmten String) erfüllen.
  18. Welche Arten von Programm(ier)fehlern kennen Sie? Wie findet man diese Fehler?
  19. Was ist der Aufrufstack? Erklären Sie den Verwendungszweck und die Funktionsweise.
Praxis:
In diesem Blog gibt es bereits eine Reihe von Aufgaben. Vergleichen Sie Ihre Lösungen mit jenen Ihrer MitschülerInnen.
Hier noch ein paar "Grundübungen":
  1. Erstellen Sie ein Pythonprogramm, welches das Maximum einer Sequenz ermittelt. Definieren Sie dazu eine fixe Testsequenz mit folgenden Werten [-1, -23, -2, -32, -89, -100, -1, -99]. Finden Sie weitere Beispieltestdaten.
  2. Erstellen Sie ein Pythonprogramm, welches das Minimum einer Sequenz ermittelt. Definieren Sie dazu eine fixe Testsequenz mit folgenden Werten [1, 23, 2, 32, 89, 100, 1, 99]. Finden Sie weitere Beispieltestdaten.
  3. Erstellen Sie ein Pythonprogramm, welches die Häufigkeit von Elementen einer Sequenz (Liste) ermittelt. Definieren Sie dazu eine Testsequenz mit folgenden Werten [1, 2, -3, 4, 2, 1, 10, -3, 4, 2, 2, 10] bzw. ["hallo", "du", "test", "du", "Maus", "test", "Test"]. Das Ergebnis soll eine Liste von unterschiedlichen Werten sein und wie oft sie vorkommen.
  4. Folgende Ausgabe soll erzeugt werden: 1 3 5 7 9. Lösen Sie die Aufgabe
    • mithilfe einer while-Schleife
    • mithilfe einer for-Schleife und des Modulo-Operators
    • mithilfe einer for-Schleife ohne den Modulo-Operator

  5. Folgende Ausgabe soll erzeugt werden: 1 2 4 7 11 16 22 29 37. Lösen Sie die Aufgabe
    • mithilfe einer while-Schleife
    • mithilfe einer for-Schleife

Labels: , ,


Montag, 21. Oktober 2013

 

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

Abgabename: 2013_2bhif_aufgabe5_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/2013_2bhif_aufgabe5_gruppeneinteilung.pdf.

Labels: , , ,


Freitag, 11. Oktober 2013

 

Aufgabe newprog.py (POS1: 2BHIF)

Abgabename: 2013_2bhif_aufgabe4_name_vorname.tgz

Neue Programmdateien haben im Allgemeinen eine ziemlich fixe (Anfangs-)Struktur. So wird immer ein Programmkopf (Kommentar) benötigt, der den Namen des Autors und andere Informationen enthält. Für Python sieht das z.B. so aus:

"""
author: Maier Maria
matnr:  d84123
file:   newprog.py
desc:   Erstellen eines Programmgerüsts aus einer Vorlage.
date:   2010-10-22
class:  5AHDVK
catnr:  23
"""

Schreiben Sie ein Pythonprogramm newprog.py, welches aus einer Vorgabedatei so ein Programmgerüst erzeugt. In dieser Vorgabedatei gibt es Wörter, die dann von newprog.py durch die entsprechenden Werte ersetzt werden. Obiges Gerüst ist aus folgender Vorgabedatei entstanden:

"""
author: AUTOR
matnr:  EVIDENZNUMMER
file:   DATEINAME
desc:   ZWECK
date:   DATUM
class:  KLASSE
catnr:  KATALOGNUMMER
"""

if __name__ == '__main__':
    pass

Für die Ersetzungen soll ein Dictionary verwendet werden, z.B.:

ersetzungen = {
    "DATEINAME": progname,
    "ZWECK": zweck,
    "DATUM": datum,
    "AUTOR": "Maier Maria",
    "KATALOGNUMMER": "23",
    "EVIDENZNUMMER": "d84123",
    "KLASSE": "5AHDVK"
}

progname, zweck, datum müssen natürlich vorher bestimmt werden (eingegeben).

Zur Bestimmung des Datums verwenden Sie strftime():

from time import strftime
datum = strftime("%F")

strftime() kennt verschiedenste Formatangaben und liefert die aktuelle Uhrzeit bzw. Datum formatiert zurück. Hilfe mit help(strftime) in Python bzw. man strftime von der Shell (liefert die Beschreibung der C-Funktion, aber die Formatangaben gelten auch für Python).

Die Vorgabedatei und der Name der zu erzeugenden Datei sind auf der Kommandozeile anzugeben, z.B.:

~/work/tmp > python newprog.py vorgabe.py meinNeuesProgramm.py
~/work/tmp >

Wird keine Vorgabedatei angegeben, so wird eine Standardvorgabedatei verwendet:

~/work/tmp > python newprog.py meinNeuesProgramm.py
~/work/tmp >

Falls meinNeuesProgramm.py schon existiert, dann darf diese Datei nicht überschrieben werden:

~/work/tmp > python newprog.py meinNeuesProgramm.py
'meinNeuesProgramm.py' already exists!
~/work/tmp >

Sie können dazu folgende Funktion verwenden (Aufrufbeispiel im Home-Verzeichnis):

>>> from os.path import exists
>>> exists(".bashrc")
True
>>> exists(".bashrc__")
False
>>> 

Labels: , ,


Mittwoch, 9. Oktober 2013

 

Musterlösung zu Aufgabe 2 "Denksport mit Python, erste Anwendung von Mercurial" (POS1: 2BHIF)

Mögliche Lösungen zur Aufgabe 2 "Denksport mit Python, erste Anwendung von Mercurial sind (nur die Python-Scrips):
#!/usr/bin/env python3
"""
 File:    pythagorean_triple.py
 Desc:    Ein Programm zur Bestimmung eines pythagoräischen Tripel (a2+b2=c2
          für a < b < c), wobei a+b+c == 1000.
 Created: 2013-09-23, Harald R. Haberstroh
"""
from sys import argv
from math import sqrt


if __name__ == '__main__':
    summe = 1000
    if len(argv) == 2:
        summe = int(argv[1])
    for a in range(1, summe // 3):
        for b in range(a + 1, summe // 2):
            a2 = a * a
            b2 = b * b
            c2 = a2 + b2
            c = sqrt(c2)
            if a < b < c and a + b + c == summe:
                print(a, b, int(c))
                print(int(a * b * c))
#!/usr/bin/env python3
"""
 File:    sumdigits2pow1000.py
 Desc:    calculate the sum of the digits of 2**1000 (exponent can be changed
          with commandline argument)
 Created: 2013-09-23, Harald R. Haberstroh
"""

from sys import argv

if __name__ == '__main__':
    if len(argv) == 2:
        exponent = int(argv[1])
    else:
        exponent = 1000
    print(sum(list(map(int, list(str(2 ** exponent))))))
#!/usr/bin/env python3
"""
 File:    sumdigitsfact.py
 Desc:    calculate the sum of the digits of 100! (100 can be changed
          with commandline argument)
 Created: 2013-09-23, Harald R. Haberstroh
"""

from sys import argv

def fact(n):
    """n!"""
    f = 1
    for i in range(1, n + 1):
        f *= i
    return f

if __name__ == '__main__':
    if len(argv) == 2:
        n = int(argv[1])
    else:
        n = 100
    print(sum(list(map(int, list(str(fact(n)))))))

Die Palindrom-Beispiele sind ganz ähnlich und wurden daher in ein Programm gepackt, bei dem man als Parameter auf der Kommandozeile die Anzahl der Stellen angeben kann (4, 6, 8). Zusätzlich kann noch '-l' angegeben werden, um eine Liste der Produkte zu erhalten. Die Ergebnisliste ist nicht ganz vollständig, denn es wird das Ergebnis des Produkts als Schlüssel verwendet. Damit gehen Lösungen wie zum Beispiel 111111 = 143 * 777 = 231 * 481 = 259 * 429 verloren.
#!/usr/bin/env python3
"""
 File:    palindrome.py
 Desc:    largest palindrome of product of two n/2-digit numbers with n digits
 Created: 2013-09-23, Harald R. Haberstroh
"""

from sys import argv

def checkPalindrom(s):
    """
    checks whether string is a palindrome
    """
    l = len(s)
    for i in range(l // 2):
        if s[i] != s[l - i - 1]:
            return False
    return True

def genPalindrom(n):
    """
    build palindrome out of products
    """
    # Dictionary only for list of palindromes not for maximum
    palindromes = {}
    products = []
    maxPalindrome = 0
    maxPalindromeFactors = ""
    for i in range(10**((n - 1) // 2), 10 ** (n // 2)):
        for j in range(10**((n - 1) // 2), 10 ** (n // 2)):
            product = str(i * j)
            if checkPalindrom(product):
                if not product in palindromes:
                    palindromes[product] = str(i) + " * " + str(j) + " = " + product
                    products.append(product)
                    if int(product) > maxPalindrome:
                        maxPalindrome = int(product)
                        maxPalindromeFactors = str(i) + " * " + str(j) + " = " + product
    return maxPalindromeFactors, palindromes

if __name__ == '__main__':
    n = 2
    if len(argv) > 1:
        n = int(argv[1])
    maxPalindrome, palindromes = genPalindrom(n)
    if "-l" in argv:
        lstPalindromes = list(palindromes.values())
        lstPalindromes.sort()
        for palindrome in lstPalindromes:
            print(palindrome)
    print("largest palindrome: %s" % maxPalindrome)

Labels: , ,


 

Musterlösung zu Wiederholung Python (POS1: 2BHIF)

Eine mögliche Lösung zur Aufgabe Wiederholung Python (POS1: 2BHIF) ist folgende:
"""
text_analyzer.py
Task 1: Repeat previous material (1st class)
2012-09-10, Harald R. Haberstroh (hp@htlwrn.ac.at)
"""


def input_sentences():
    '''returns al list of sentences/lines'''
    lst = []
    eof = False
    while not eof:
        try:
            line = input("Satz: ")
            lst.append(line)
        except EOFError:
            eof = True
    return lst


def _remove_punctuation(string):
    '''helper removes all punctuation marks within string'''
    for punctuation in '''"',;.:-''':
        string = string.replace(punctuation, " ")
    return string


def split_sentences(lst):
    '''split a list (lst) of sentences into list of list of words'''
    wordlist = []
    for sentence in lst:
        wordlist.append(_remove_punctuation(sentence).split())
    return wordlist


def purge_bad_words(lst):
    '''remove all bad words (length less than 2 chars, words
    containing non alphabetic chars)
    '''
    for sublist in lst:
        idx = 0
        while idx < len(sublist):
            if not len(sublist[idx]) >= 2 or not sublist[idx].isalpha():
                del(sublist[idx])
            else:
                idx += 1
    return lst


def analyze_words(lst):
    '''returns a dictionary of words (with the number of occurrences)
    of the list of list of words'''
    dict = {}
    for sublist in lst:
        for word in sublist:
            word = word.lower()
            if word in dict:
                dict[word] += 1
            else:
                dict[word] = 1
    return dict

def analyze_letters(lst):
    '''returns a dictionary of letters (with the number of occurrences)
    of the list of list of words'''
    dict = {}
    for sublist in lst:
        for word in sublist:
            for char in word.lower():
                if char in dict:
                    dict[char] += 1
                else:
                    dict[char] = 1
    return dict
                

def purge_analyzed_letters(dic):
    '''remove umlauts'''
    for umlaut in "äöüß":
        if umlaut in dic:
            del(dic[umlaut])
    return dic


def _key(tupl):
    '''returns 2nd element of tuple for sorting'''
    return tupl[1]


def sort_letters(dic):
    '''returns a sorted list of tuples of letters, sorted by
    number of letters'''
    tuples = list(dic.items())
    tuples.sort(key=_key, reverse=True)
    return tuples


def test_input():
    '''returns a fixed list of sentences for testing purposes'''
    return ['Maxi und Mini verliefen sich im Wald, aber bald.',
        '10 alte Fledermäuse flogen im Wald',
        'Hat die alte Meisterhexe...',
        "Seid's gewesen. Denn als Geister...",
        'Erst hervor der alte Meister.']


if __name__ == '__main__':
    #lst = input_sentences()
    lst = test_input()
    
    print('split_sentences(lst)')
    wordlist = split_sentences(lst)
    print(wordlist)
    
    print('\npurge_bad_words(wordlist)')
    wordlist = purge_bad_words(wordlist)
    print(wordlist)

    print('\nanalyze_words(wordlist)')
    print(analyze_words(wordlist))

    print('\nanalyze_letters(wordlist)')
    dic = analyze_letters(wordlist)
    print(dic)

    print('\npurge_analyzed_letters(dic)')
    dic = purge_analyzed_letters(dic)
    print(dic)

    print('\nsort_letters(dic)')
    sorted_letters = sort_letters(dic)
    print(sorted_letters)

    print('\n\n*** task 9 ***\n')
    print('''"abcdef".index("c")''') # ValueError: substring not found
    print('''ValueError: substring not found''')
    print('''"abcdef".index("g")''') # ValueError: substring not found
    print('''ValueError: substring not found''')
    print('''"abcdef".index("de")''')
    print("abcdef".index("de"))
    print('''"c" in "abcdef" ''')
    print("c" in "abcdef")
    print('''"g" in "abcdef" ''')
    print("g" in "abcdef")
    print('''"de" in "abcdef" ''')
    print("de" in "abcdef")
    print('''"abcdef"[2:4]''')
    print("abcdef"[2:4])
    print('''"abcdef"[2:]''')
    print("abcdef"[2:])
    print('''"abcdef"[-1]''')
    print("abcdef"[-1])
    print('''"abcdef"[2:-1]''')
    print("abcdef"[2:-1])
    print('''[1, 2, 3, 4, 5].index(3)''')
    print([1, 2, 3, 4, 5].index(3))
    print('''[1, 2, 3, 4, 5].index(9)''') # ValueError: 9 is not in list
    print('''ValueError: 9 is not in list''')
    print('''[1, 2, 3, 4, 5][5]''') # IndexError: list index out of range
    print('''IndexError: list index out of range''')
    print('''[1, 2, 3, 4, 5][2:4]''')
    print([1, 2, 3, 4, 5][2:4])
    print('''[1, 2, 3, 4, 5][-2]''')
    print([1, 2, 3, 4, 5][-2])
    print('''[1, 2, 3, 4, 5][5:9]''')
    print([1, 2, 3, 4, 5][5:9])
    print('''[1, 2, 3, 4, 5][4:]''')
    print([1, 2, 3, 4, 5][4:])
    print('''len("abc") + len(range(3)) + len({1, 2, 3}) + len({1: 2, 2: 3})''')
    print(len("abc") + len(range(3)) + len({1, 2, 3}) + len({1: 2, 2: 3}))

Labels: , ,


Montag, 7. Oktober 2013

 

Aufgabe Python Kommandozeile, Textdateien lesen (POS1: 2BHIF)

Abgabename: 2013_2bhif_aufgabe3_name_vorname.tgz (nur Kleinbuchstaben)

Schreiben Sie folgendes Pythonprogramm: cut.py, welches einen bestimmten Zeilenbereich der Eingabe (Text) ausgibt (und den Rest unterdrückt). Die Eingabe kann aus beliebig vielen Dateien, die als Kommandozeilenparameter angegeben werden, oder aus der Standardeingabe (Tastatur oder Eingabe umlenkung mit <) bestehen.

Für jede Datei soll dann der als Optionen angegebene Zeilenbereich ausgegeben werden.

Aufruf

cut.py [-f N] [-t N] [-h] [file]...
Falls keine Optionen angegeben werden, dann sollen die ersten 10 Zeilen jeder Datei (oder Standardeingabe) ausgegeben werden.

Optionen

-f N
Der Zeilenbereich beginnt ab Zeile N. Entfällt diese Option, dann beginnt die Ausgabe bei der ersten Zeile.
-t N
Der Zeilenbereich endet bei Zeile N (inklusive). Entfällt diese Option, dann endet die Ausgabe bei der Zeile 10.
-h
Es soll eine kurze Hilfe mit ihrem Namen ausgegeben werden. Zum Beispiel:
cut.py [-f N] [-t N] [file]...
  -f N ... from line N (default 1)
  -t N ... to line N (default 10)
Print given lines of each file.

(c) 2012, Harald R. Haberstroh
Es soll keine weitere Ausgabe erfolgen!

Beispiel

Gegeben sei die Datei 1.txt mit dem Inhalt (Zeilennummern nur zur Orientierung, nicht Inhalt der Datei):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit 
amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut 
labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam 
et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata 
sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur 
sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore 
magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo 
dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est 
Lorem ipsum dolor sit amet.   
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie 
consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan
et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis 
dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet,
hh@knuth:~$ cut.py -h
cut.py [-f N] [-t N] [file]...
  -f N ... from line N (default 1)
  -t N ... to line N (default 10)
Print given lines of each file.

(c) 2012, Harald R. Haberstroh
hh@knuth:~$ cut.py 1.txt
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit 
amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut 
labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam 
et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata 
sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur 
sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore 
magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo 
hh@knuth:~$ cut.py -f 3 -t 12 1.txt
vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit 
amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut 
labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam 
et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata 
sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur 
sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore 
magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo 
dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est 
Lorem ipsum dolor sit amet.
hh@knuth:~$ cut.py -t 3 1.txt
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
Überlegen Sie, was das Programm bei fehlerhaften Angaben machen soll!

Beispiele für fehlerhafte Angaben

Eine ungültige Option wird angegeben:
hh@knuth:~$ cut.py -x 23 1.txt
Es fehlt der Parameter bei den Optionen, hier bei -t:
hh@knuth:~$ cut.py -f 23 -t 1.txt
"To" ist kleiner als "From":
hh@knuth:~$ cut.py -f 23 -t 12 1.txt
Datei existiert nicht:
hh@knuth:~$ cut.py doesntexist.txt

Labels: , ,


Montag, 30. September 2013

 

Python Kommandozeilenparameter

Kommandozeile (unter Linux/Unix)

Gleich zur Kommandozeilenbearbeitung mit Python
Folgender Artikel gibt einen kurzen Einblick in die Geschichte der Kommandozeile: Commandline resurrected.

Viele Aufgaben lassen sich auch wesentlich schneller auf der Kommandozeile erledigen als mit der grafischen Oberfläche (Click-Click-Drag usw). Ein paar Beispiele (Shell bedeutet hier Kommandozeile):

Suche alle .c Dateien, die neuer sind als Makefile.


Shell... find . -name ' *.c' -newer Makefile -print
GUI... Öffne den Explorer, navigiere zum entsprechenden Verzeichnis, Klicke auf die Datei Makefile und merke das Änderungsdatum bzw. Zeit. Dann Starte Tools/Find und gib *.c als Suchkriterium ein. Wähle den Datumsreiter und gib das gemerkte Datum ein. Klicke OK.

Erzeuge an zip/tar-Archiv meines Sourcecodes (C-Code).


Shell... zip archive.zip *.h *.c oder tar cvf archive.tar *.h *.c
GUI... Öffne ein ZIP-Werkzeug (z.B. WinZip), wähle "Neues Archiv", gib den Namen ein, wähle das (Quell-)Verzeichnis im Hinzufügen Dialog, setze den Filter auf *.c und klicke "Hinzufügen", dann setze einen weiteren Filter auf *.h und klicke "Hinzufügen" und schließe das Archiv wieder.

Ein letztes Beispiel:

Welche Java-Dateien wurden letzte Woche geändert?


Shell... find . -name '*.java' -mtime +7 -print
GUI... Klicke und navigiere zu "Suche Dateien", klicke auf "Name" und gib "*.java" ein, wähle "Datum letzte Änderung" und klicke auf "Beginndatum", gib das Startdatum des Projekts ein (wann war das, verd**** noch mal?). Weiters klicke auf "Endedatum" und gib das Datum von vor einer Woche ein (schau mal schnell auf einen Kalender...). Klicke "Suche".
Anmerkung: Möglicherweise sind die genauen Bezeichnungen bzw. Beschriftungen beim GUI nicht ganz korrekt, denn die hängen von der Version sowie von Typ der Grafischen Oberfläche (GUI = Graphical User Interface) ab. Die (Shell-) Befehle sind jedoch korrekt.

Befehls-Syntax

Unix (Linux) Befehle haben folgende einheitliche Struktur. Bis auf den Befehlsnamen (Programmname) sind grundsätzlich alle anderen Angaben optional.
Befehlsname [Option...] [Argument...] [Ein-/Ausgabeumlenkung]
Die eckigen Klammern deuten an, dass dieser Parameter optional ist. Die drei Punkte geben zusätzlich an, dass mehrere solcher Parameter möglich sind.
Optionen sind syntaktisch von anderen Argumenten unterscheidbar: sie beginnen mit einem Minus, haben einen Buchstaben und danach optional ein Argument für diese Option
-x [Argument]
oder sie beginnen mit zwei Minus und einem Optionsnamen sowie dem optionalen Argument.
--Optionsname [Argument]

Befehlsargumente sind Dateinamen oder andere für den Befehl wichtige Informationen.
Normalerweise lesen Unix-Programme Eingaben vom Terminal und geben Ausgaben auf das Terminal aus. Diese Datenkanäle können durch Ein-Ausgabeumlenkung geändert werden. Diese Umleitungen unterscheiden sich ebenfalls von den Optionen und anderen Argumenten (< Eingabedatei, > Ausgabedatei und | für die Pipe).
<
Das Kommando liest von der angegebenen Datei (statt von der Tastatur).
>
Das Kommando schreibt in die angegebene Datei (statt auf das Terminal).
|
Die Ausgabe des Kommandos links vom | wird als Eingabe für das Kommando rechts vom | verwendet. Die Kommandos sind über eine Pipe (Leitung, Rohrleitung) verbunden.
Ein paar Beispiele:
hh@knuth:~$ cd workspace
hh@knuth:~/workspace$ ls
c2bf  demo  eclimd.log  guidemo  libbf  programmierblog  python  python3  python-sum
pythontest  pythonX  scm-demo  _SCRIPTS_  unit-tests
hh@knuth:~/workspace$ cd c2bf
hh@knuth:~/workspace/c2bf$ ls
1tox  cc  GPL  ld  Makefile  math  README  strip  test.sh  wrapper
hh@knuth:~/workspace/c2bf$ cd cc
hh@knuth:~/workspace/c2bf/cc$ ls
ast.h  c2bf-cc  c2bf-dispast  dispast.c  dispast.o  genbf  genbf.h  genbfmain.c
genbfmain.o  gram.o  gram.y  main.c  main.o  Makefile  README.txt  scan.l  
scan.o  tests  y.output  y.tab.h
hh@knuth:~/workspace/c2bf/cc$ ls *.c *.h
ast.h  dispast.c  genbf.h  genbfmain.c  main.c  y.tab.h
hh@knuth:~/workspace/c2bf/cc$ ls -l *.c *.h
-rw-rw-r-- 1 hh hh 21061 Aug 31 21:40 ast.h
-rw-rw-r-- 1 hh hh 30503 Aug 31 21:40 dispast.c
-rw-rw-r-- 1 hh hh  6627 Aug 31 21:40 genbf.h
-rw-rw-r-- 1 hh hh   953 Aug 31 21:40 genbfmain.c
-rw-rw-r-- 1 hh hh   917 Aug 31 21:40 main.c
-rw-rw-r-- 1 hh hh  7631 Aug 31 21:45 y.tab.h
hh@knuth:~/workspace/c2bf/cc$ cd
hh@knuth:~$
Mehr Informationen zur Shell (Kommandozeile) gibt es hier: Bash (Shell)

Kommandozeilenparameter mit Python bearbeiten

Das (Standard-) Modul sys ermöglicht es von Python auf die Umgebung, in der Python läuft, zuzugreifen. In unserem Fall wenden wir uns der Kommandozeile zu.
#!/usr/bin/python3
import sys

print("commandline:")
for arg in sys.argv:
    print(arg)
hh@knuth:/tmp$ vim cmd.py 
hh@knuth:/tmp$ cat cmd.py 
#!/usr/bin/python3
import sys

print("commandline:")
for arg in sys.argv:
    print(arg)
hh@knuth:/tmp$ python3 cmd.py -o --option par1 par2
commandline:
cmd.py
-o
--option
par1
par2
hh@knuth:/tmp$ chmod +x cmd.py 
hh@knuth:/tmp$ ./cmd.py -o --option par1 par2
commandline:
./cmd.py
-o
--option
par1
par2
hh@knuth:/tmp$ 
Die Zeile
#!/usr/bin/python3
dient dazu, dem Betriebssystem zu sagen, mit welchem Programm diese (Text-) Datei zu starten ist, wenn man sie mit chmod +x file ausführbar gemacht hat.

Sie sehen, dass alle Parameter nach python3 ausgegeben werden. Ist die Pythondatei ausführbar, bekommt man die (fast) dieselbe Ausgabe (./ vor einem Kommando bedeutet, dass dieses Kommando im aktuellen Verzeichnis und nicht im Pfad zu finden ist).
hh@knuth:/tmp$ python3
Python 3.2.3 (default, Sep 10 2012, 18:14:40) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> type(sys.argv)
<class 'list'>
>>> 
sys.argv ist eine Liste, die alle Kommandozeilenparameter inklusive des Scriptnamens enthält. Das Pythonprogramm muss die Argumente entsprechend behandeln: Optionen erkennen, Argumente verwenden. Nur die Ein-/Ausgabeumlenkung braucht man nicht im Programm behandeln (solange man nur die Standardkanäle verwendet).
hh@knuth:/tmp$ ./cmd.py -o --option par1 par2 > outputfile
hh@knuth:/tmp$ cat outputfile
commandline:
./cmd.py
-o
--option
par1
par2
hh@knuth:/tmp$ 
Bei der Ausgabeumleitung auf die Datei outfile "verschwindet" die Ausgabe in dieser Datei.

Ein einfaches Beispiel, das den "Typ" der Argumente ausgibt:
import sys

def info(progname):
    """print some information"""
    print(str.format("""
usage:
    {0} [-h] [parameter...]
prints type of parameters

Options:
-h ... this help

(c) 2012 Harald R. Haberstroh
    """, progname))
    
    
if __name__ == '__main__':
    if "-h" in sys.argv:
        info(sys.argv[0])
    else:
        for arg in sys.argv:
            if arg.isdigit():
                print("number", arg)
            elif arg.isalpha():
                print("word", arg)
            else:
                print("string", arg)
hh@knuth:/tmp$ python3 cmdline.py 123 Harald '+$' -h

usage:
    cmdline.py [-h] [parameter...]
prints type of parameters

Options:
-h ... this help
    
(c) 2012 Harald R. Haberstroh
hh@knuth:/tmp$ python3 cmdline.py 123 Harald '+$' 
string cmdline.py
number 123
word Harald
string +$
hh@knuth:/tmp$
Ihre Python-Programme sollten immer eine Hilfe mit der Option -h oder --help anbieten. Dort muss auch Ihr Name und die Klasse ausgegeben werden.

Nach der Ausgabe der Hilfe (Info) soll das Programm beendet werden. Damit kann man wie im obigen Beispiel einfach -h an die Kommandozeile anhängen.

In der Hilfe/Info muss auch immer der Programmname wie im Beispiel ausgegeben werden (sys.argv[0])!

Labels: , ,


 

Python Objekte, Aufrufstack (POS1: 2BHIF)

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

Labels: , ,


Montag, 23. September 2013

 

Denksport mit Python, erste Anwendung von Mercurial (POS1: 2BHIF)

Abgabename: 2013_2bhif_aufgabe2_Name_Vorname.tgz

Lesen Sie Mercurial Einführung und legen Sie
  1. die Datei ~/.hgrc nach dem Muster des obigen Artikels an:
    [ui]
    username = Vorname Name <i99999@student.htlwrn.ac.at>
    
  2. ein Projekt mit dem Namen brain_teasers an.
  3. ein Mercurial Repository an.
Arbeiten Sie die Aufgaben der Reihe nach ab und nehmen Sie das jeweilige Pythonscript in das Repository auf. Machen Sie (spätestens) dann ein commit, wenn das Programm funktioniert (oder wenn es zumindest ohne Syntaxfehler läuft).

Schreiben Sie folgende Pythonprogramme:
pythagorean_triple.py
Es soll ein Pythagoreisches Tripel (a2 + b2 = c2 für a < b < c) für a + b + c == 1000.
sumdigits2pow1000.py
Es soll die Ziffernsumme (Quersumme, engl. cross sum) der Zahl 21000 ermittelt werden. Die Zahl soll als Programmargument angegeben werden.
sumdigitsfact.py
Es soll die Ziffernsumme der Fakultät von 100 (100!) ermittelt werden. Die Zahl soll als Programmargument angegeben werden.
palindrome4.py
Generiere 4-stellige Palindrome als Produkt 2-steliger Zahlen. Die Faktoren und das Palindrom soll ausgegeben werden. Da die Multiplikation kommutativ ist, müssen Duplikate entfernt werden: 74x66 == 66x74 (4884), also nur einmal ausgeben.
palindrome6.py
Generiere 6-stellige Palindrome als Produkt 3-steliger Zahlen. Gib das Maximum der Palindrome aus.

Labels: , , ,


Montag, 16. September 2013

 

Python - suchen und ersetzen einzelner Zeichen

Sie wollen in einem String zum Beispiel alle Dollar-Zeichen ($) durch Euro (€), alle Fragezeichen (?) durch Rufzeichen (!), einfache Hochkomma (') durch doppelte Hochkomma (") ersetzen und eckige Klammern ([ und ]) löschen.

Definieren Sie eine Übersetzungstabelle (Dictionary) und verwenden Sie die Methode str.translate(table)).

translation_table = {
    "$": "€",
    "?": "!",
    "'": '"',
    "[": None,
    "]": None
}

teststring = """Das ist ein Test? Der kostet ['1000$']"""
print(teststring.translate(str.maketrans(translation_table)))

Folgendes wird dann ausgegeben:

hp@if211l $ python3
Python 3.2.3 (default, Apr 10 2013, 06:11:55) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> translation_table = {
...     "$": "€",
...     "?": "!",
...     "'": '"',
...     "[": None,
...     "]": None
... }
>>>
>>> teststring = """Das ist ein Test? Der kostet ['1000$']"""
>>> print(teststring.translate(str.maketrans(translation_table)))
Das ist ein Test! Der kostet "1000€"
>>>

str.maketrans(table) erzeugt ein Dictionary mit den Unicode-Werten der Zeichen.

Tatsächlich können Sie einzelne Zeichen sogar durch ganze Strings ersetzen. Wenn Sie zB. Umlaute durch die entsprechenden HTML-Sequenzen ersetzen wollen, dann können Sie eine Tabelle wie folgt verwenden:

translation_table = {
    "Ä": "&Auml;",
    "ä": "&auml;",
    "Ö": '&Ouml;',
    "ö": "&ouml;",
    "Ü": "&Uuml;",
    "ü": "&uuml;"
}

>>> translation_table = {
...     "Ä": "&Auml;",
...     "ä": "&auml;",
...     "Ö": '&Ouml;',
...     "ö": "&ouml;",
...     "Ü": "&Uuml;",
...     "ü": "&uuml;"
... }
>>> "Übermäßig".translate(str.maketrans(translation_table))
'&Uuml;berm&auml;ßig'
>>> 

Labels:


Sonntag, 8. September 2013

 

Wiederholung Python (POS1: 2BHIF)

Abgabename: 2013_2bhif_aufgabe1_Name_Vorname.tgz

Die folgenden Aufgaben ermöglichen Ihnen einen Wiedereinstieg in das Programmieren mit Python. Das Rüstzeug zur Lösung sollten Sie in der ersten Klasse bekommen haben.
Googlen Sie nach 'python "reference card"' und suchen Sie eine passende Kurzreferenz.
  1. Schreiben Sie eine Funktion input_sentences in einem Modul text_analyzer, die den Benutzer nach beliebigen Sätzen fragt, diese in einer Liste abspeichert und danach zurückliefert. Das könnte also so aussehen:
    Bitte geben Sie die zu analysierenden Sätze ein (CTRL-D bricht ab):
    Satz: Maxi und Mini verliefen sich im Wald, aber bald.
    Satz: 10 alte Fledermäuse flogen im Wald
    Satz: Hat die alte Meisterhexe...
    Satz: Seid's gewesen. Denn als Geister...
    Satz: Erst hervor der alte Meister.
    Satz: <ctrl-d>
    
    CTRL-D bewirkt ein Ende der Eingabe (EOF ... End Of File).
  2. Fügen Sie dazu in diesem Modul einen Aufruf dieser Funktion ein, sodass das Modul sowohl als Modul als auch als Programm verwendet werden kann. Dies macht man üblicherweise folgendermaßen:
    # prüft, ob das Modul als Programm aufgerufen wurde
    if __name__ == '__main__': # main
        lst = input_sentences()
    

  3. Schreiben Sie eine Funktion split_sentences(lst), die eine Liste solcher Sätze bekommt und eine Liste von Wortlisten zurückliefert, wobei die übergebene Liste lst direkt verändert werden soll.

    Die Wortlisten entstehen indem man die Sätze an den Whitespace Zeichen und den Satzzeichen ("',;.:-) trennt. Die Satzzeichen werden nicht benötigt.

    Gehen Sie dazu folgendermaßen vor:
    1. Ersetze zuerst alle Satzzeichen hintereinander durch Leerzeichen. Verwende dazu die replace Methode des Typs str.
    2. Trenne (splitte) danach den String in die einzelnen Wörter mittels der Methode split des Typs str.
    Für die obigen Daten sieht das Ergebnis dieses Funktionsaufrufes folgendermaßen aus:
    >>> lst = ['Maxi und Mini verliefen sich im Wald, aber bald.',
    ... '10 alte Fledermäuse flogen im Wald',
    ... 'Hat die alte Meisterhexe...',
    ... "Seid's gewesen. Denn als Geister...",
    ... 'Erst hervor der alte Meister.']
    >>> split_sentences(lst)
    [['Maxi', 'und', 'Mini', 'verliefen', 'sich', 'im', 'Wald',\
    'aber', 'bald'], ['10', 'alte', 'Fledermäuse', 'flogen', 'im', 'Wald'],\
    ['Hat', 'die', 'alte', 'Meisterhexe'], ['Seid', 's', 'gewesen', 'Denn',\
    'als', 'Geister'], ['Erst', 'hervor', 'der', 'alte', 'Meister']]
    >>> lst
    [['Maxi', 'und', 'Mini', 'verliefen', 'sich', 'im', 'Wald',\
    'aber', 'bald'], ['10', 'alte', 'Fledermäuse', 'flogen', 'im', 'Wald'],\
    ['Hat', 'die', 'alte', 'Meisterhexe'], ['Seid', 's', 'gewesen', 'Denn',\
    'als', 'Geister'], ['Erst', 'hervor', 'der', 'alte', 'Meister']]
    
    Bei der obigen Ausgabe wurden zur besseren Lesbarkeit die Zeilen manuell umgebrochen und der Zeilenumbruch jeweils mit einem \ gekennzeichnet.

    Baue diese Funktion in das Hauptprogramm ein.

  4. Schreiben Sie eine Funktion purge_bad_words(lst), die eine Liste von Listen von Wörtern erhält und alle diejenigen herauslöscht, die
    • weniger als 2 Zeichen lang sind oder
    • nicht alphabetische Zeichen enthalten
    Die übergebene Liste lst soll direkt manipuliert und auch zurückgeliefert werden:
    >>> purge_bad_words(lst)
    [['Maxi', 'und', 'Mini', 'verliefen', 'sich', 'im', 'Wald', 'aber',\
    'bald'], ['alte', 'Fledermäuse', 'flogen', 'im', 'Wald'], ['Hat',\
    'die', 'alte', 'Meisterhexe'], ['Seid', 'gewesen', 'Denn', 'als',\
    'Geister'], ['Erst', 'hervor', 'der', 'alte', 'Meister']]
    
    Wie leicht zu sehen sind sind die zu kurzen Wörter und die Wörter, die nicht-alphabetische Zeichen enthalten entfernt worden.

  5. Schreiben Sie eine Funktion analyze_words(lst), die eine Liste wie aus dem vorhergehenden Punkt als Argument bekommt und ein Dictionary mit allen Worten als Keys und deren Häufigkeiten als Values zurückliefert, wobei aber alle Wörter nur klein geschrieben gezählt werden:
    >>> analyze_words(lst)
    {'wald': 2, 'mini': 1, 'aber': 1, 'gewesen': 1, 'flogen': 1, 'im': 2,\
    'hervor': 1, 'als': 1, 'verliefen': 1, 'maxi': 1, 'sich': 1,\
    'meister': 1, 'hat': 1, 'bald': 1, 'meisterhexe': 1, 'erst': 1,\
    'fledermäuse': 1, 'geister': 1, 'die': 1, 'alte': 3, 'und': 1,\
    'denn': 1, 'seid': 1, 'der': 1}
    

  6. Schreiben Sie eine Funktion analyze_letters(lst), die wiederum eine Liste der Liste der Wörter bekommt und ein Dictionary mit Buchstaben als Keys und deren Häufigkeiten als Values zurückliefert. Wiederum werden alle Buchstaben als Kleinbuchstaben betrachtet:
    >>> analyze_letters(lst)
    {'a': 10, 'c': 1, 'b': 2, 'e': 28, 'd': 9, 'g': 3, 'f': 3, 'i': 12,\
    'h': 4, 'm': 7, 'l': 10, 'o': 2, 'n': 7, 's': 9, 'r': 10, 'u': 2,\
    't': 8, 'w': 3, 'v': 2, 'x': 2, 'ä': 1}
    

  7. Schreiben Sie nun eine Funktion purge_analyzed_letters(dic), die alle Umlaute (ä, ü, ö) aus dem Dictionary (des vorhergehenden Punktes) entfernt:
    >>> purge_analyzed_letters(dic)
    {'a': 10, 'c': 1, 'b': 2, 'e': 28, 'd': 9, 'g': 3, 'f': 3, 'i': 12,\
    'h': 4, 'm': 7, 'l': 10, 'o': 2, 'n': 7, 's': 9, 'r': 10, 'u': 2,\
    't': 8, 'w': 3, 'v': 2, 'x': 2}
    

  8. Entwicklen Sie eine Funktion sort_letters(dic), die ein Dictionary wie aus dem vorhergehenden Punkt bekommt und eine absteigend sortierte Liste von Tupel mit Buchstabe und Häufigkeit zurückliefert:
    >>> sort_letters(dic)
    [('e', 28), ('i', 12), ('a', 10), ('l', 10), ('r', 10), ('d', 9),\
    ('s', 9), ('t', 8), ('m', 7), ('n', 7), ('h', 4), ('g', 3), ('f', 3),\
    ('w', 3), ('b', 2), ('o', 2), ('u', 2), ('v', 2), ('x', 2), ('c', 1)]
    

  9. Probieren Sie aus:
    1. "abcdef".index("c")
    2. "abcdef".index("g")
    3. "abcdef".index("de")
    4. "c" in "abcdef"
    5. "g" in "abcdef"
    6. "de" in "abcdef"
    7. "abcdef"[2:4]
    8. "abcdef"[2:]
    9. "abcdef"[-1]
    10. "abcdef"[2:-1]
    11. [1, 2, 3, 4, 5].index(3)
    12. [1, 2, 3, 4, 5].index(9)
    13. [1, 2, 3, 4, 5][5]
    14. [1, 2, 3, 4, 5][2:4]
    15. [1, 2, 3, 4, 5][-2]
    16. [1, 2, 3, 4, 5][5:9]
    17. [1, 2, 3, 4, 5][4:]
    18. len("abc") + len(range(3)) + len({1, 2, 3}) + len({1: 2, 2: 3})

    Speichern Sie die Aufrufe und das Ergebnis in einer Datei log.txt, welche Sie dann mit abgeben.

  10. Bauen Sie in ihr Main Testaufrufe aller Funktionen mit einer fixen Liste auf (Kommentieren Sie den Aufruf von input_sentences() aus). Es soll jedes Stadium der Verarbeitung der Liste ausgegeben werden. Bauen Sie die Aufrufe aus obigem Punkt (Probieren Sie aus) ein und geben Sie das Ergebnis aus. Man muss den Programmcode (print() verwenden) sehen und das Ergebnis.

  11. Geben Sie das Beispiel ab, indem Sie text_analyzer.py und log.txt in ein Archiv mit dem Namen Abgabename: 2013_2bhif_aufgabe1_Name_Vorname.tgz (Name ist Ihr Familienname und Vorname ist Ihr Vorname, wobei Sie Umlaute und scharfes s durch ASCII-Zeichen ersetzen müssen, also z.B. 2013_2bhif_aufgabe1_grossauer_guenter.tgz für Günter Großauer) packen und diese Datei auf dem edvossh.htlwrn.ac.at nach /home/teachers/hp/abgabe/2bhif/ kopieren.
    Beachten Sie, dass Sie das oben angegebene Verzeichnis nicht lesen können, Sie können in dieses Verzeichnis wohl aber schreiben.
    Denken Sie an den Header, der etwa so aussehen muss:
    """
    author: Großauer, Günter
    matnr:  i09666
    file:   bubblesort.py
    desc:   sort lists with bubblesort
    date:   2013-09-08
    class:  2bhif
    catnr:  33
    """
    


Das Original zu dieser Aufgabe stammt von Dr. Kolousek.

Labels: , ,


Donnerstag, 4. Juli 2013

 

XML Datei aus einer ZIP-Datei mit Python ändern und wieder zurückschreiben (Hack für Probleme mit K3B und diversen MP3-Playern)

Der Titel sagt's bereits. Dieses kleine Script ändert den Inhalt einer XML-Datei in einer ZIP-Datei. Konkret handelt es sich um eine Projektdatei des Linux-Brennprogrammes k3b. Ich erstelle damit CDs für's Autoradio mit MP3s. Allerdings enthält die CD die Dateien in alphabetischer Reihenfolge und das Autoradio spielt das in der Reihenfolge ab. Ich habe keinen anderen Weg gefunden, als die Dateinamen entsprechend zu ändern. Das ist natürlich in einer grafischen Oberfläche mühsam.

Mit k3b erzeuge ich ein neues Projekt, in dem ich die Songs in der Reihenfolge, die ich haben will hinzufüge. Dann speichere ich das Projekt und lasse die Dateinamen durch das Script in der Projektdatei ändern. Dann lade ich das Projekt und brenne die CD. Die Lieder sind dann in der richtigen Reihenfolge, weil die Namen mit einer Nummer wie hier 001 - Lied.mp3 versehen werden.

#!/usr/bin/env python
"""
change entries so that they are sorted by name used with k3b-data CDs (mp3
CDs).

Procedure:
    1. make k3p project and add files.
    2. save this project
    3. close the project (leave k3b open)
    4. run this script: numbermymp3.py your_project_name.k3p
    4. load the project again.
    5. as you can see, the files ar starting with 3-digit numbers preserving
       the original order when adding the files.

2013-07-04, Harald R. Haberstroh
"""
import sys
import codecs
import zipfile
from xml.dom import minidom

def getfiles(zipfilename):
    """get dictionary filename:data with all files in zipfile"""
    zf = zipfile.ZipFile(zipfilename)
    files = {}
    for info in zf.infolist():
        files[info.filename] = zf.read(info.filename)
    return files

def process(xmlstr):
    """process xml with file entries and change 'name' attribute according
    to number of file (starting with 001)."""
    xmldoc = minidom.parseString(xmlstr)
    names = xmldoc.getElementsByTagName('file')
    num = 1
    for name in names:
        numstr = "%03d" % num
        name.attributes['name'].value = numstr + ' - ' + \
                name.attributes['name'].value
        num += 1
    return xmldoc.toprettyxml().encode('utf-8')

def genzipfile(zipfilename, files):
    """generate new zipfile (k3b-file) with dict 'files' which has file name as
    key and the content as data"""
    zf = zipfile.ZipFile(zipfilename, mode='w')
    try:
        for name in files:
            zf.writestr(name, files[name])
    finally:
        zf.close()

def main():
    """all to gether now"""
    if len(sys.argv) != 2:
        print "usage: " + sys.argv[0] + " k3b_project_name.k3b"
        print "renames files so that the order is the same as in the project"
        sys.exit(1)
    fname = sys.argv[1]
    files = getfiles(fname)
    text = process(files['maindata.xml'])
    files['maindata.xml'] = text
    genzipfile(fname, files)

if __name__ == '__main__':
    main()

Labels: ,


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

Abonnieren Posts [Atom]