12. Ingenieurwissenschaftliches Arbeiten

In den Ingenieurswissenschaften kommt dem Scientific Computing (d.h. der Numerik) ein immer größerer Stellenwert zu (siehe Abbildung Scientific Computing in Python).

_images/python_scientific.png

Scientific Computing in Python

Python und IPython haben wir bereits kennen gelernt. In diesem Kapitel werden wir die Bibliotheken:

  • NumPy
  • Scipy
  • Matplotlib
  • Jupyter

genauer kennen lernen.

Einige kennen wahrscheinlich Matlab. Python in Kombination mit NumPy, SciPy, Matplotlib und Pandas kann als vollwertiger Ersatz für MATLAB genutzt werden.

_images/python_matlab.png

12.1. NumPy

NumPy ist ein Akronym für “Numerisches Python”.

Das Modul wird importiert mittels :

import numpy

Wesentlich häufiger findet man jedoch die Abkürzung:

import numpy as np

12.1.1. Erzeugung von Arrays

NumPy Arrays können einfach aus Python Listen erzeugt werden:

In [1]: import numpy as np              # Import des Moduls

In [2]: a = np.array([2, 4, 5, 9])      # Erzeuge NumPy Array aus Liste

In [3]: a
Out[3]: array([2, 4, 5, 9])             # 'array' zeigt den Objecttyp an

In [4]: type(a)                         # Objecttyp Abfrage
Out[4]: numpy.ndarray

In [5]: a.dtype                         # Datentyp Abfrage
Out[5]: dtype('int32')

Alternativ kann man NumPy Funktionen zur Erzeugung verwenden:

In [1]: b = np.zeros((2, 3))            # Erzeuge 2D Array mit "0"

In [2]: b
Out[2]:
array([[0., 0., 0.],
       [0., 0., 0.]])

In [3]: c = np.ones((2,3,4), np.int)    # 3D Array mit "1", Datentyp Integer

In [4]: c
Out[4]:
array([[[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]],

       [[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]]])

NumPy bietet Funktionen, um Arrays aus Intervallen zu erzeugen:

In [1]: import numpy as np

In [2]: a = np.arange(1,7)                # Array mittels Intervall: start, stop

In [3]: a                                 # Objecttyp: numpy.ndarray
Out[3]: array([1, 2, 3, 4, 5, 6])

In [4]: c = np.arange(4, dtype=np.float)  # 1D array mit Datentyp Angabe

In [5]: c
Out[5]: array([0., 1., 2., 3.])

Die arange Funktion sollte nicht mit der Standard Python range Funktion verwechselt werden:

In [1]: x = range(1,7)                    # Standard Python range Funktion

In [2]: x
Out[2]: range(1, 7)                       # .. ist ein Iterator

In [3]: list(x)                           # Umwandlung in Liste
Out[3]: [1, 2, 3, 4, 5, 6]

12.1.2. Grundlegende Rechenoperationen

Einige Grundlegen Rechenoperationen mit NumPy-Arrays lauten:

In [1]: import numpy as np

In [2]: a = np.array( [20,30,40,50] )

In [3]: b = np.arange( 4 )

In [4]: b
Out[4]: array([0, 1, 2, 3])

In [5]: c = a-b

In [6]: c
Out[6]: array([20, 29, 38, 47])

In [7]: b**2
Out[7]: array([0, 1, 4, 9], dtype=int32)

In [8]: 10*np.sin(a)
Out[8]: array([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854])

In [9]: a<35
Out[9]: array([ True,  True, False, False])

Anders als in vielen Matrixsprachen arbeitet der Produktoperator * in NumPy-Arrays Elementweise. Das Matrixprodukt kann mit dem Operator @ (in Python> = 3.5) oder der Funktion dot ausgeführt werden:

In [10]: A = np.array( [[1,1],
    ...:                [0,1]] )

In [11]: B = np.array( [[2,0],
    ...:                [3,4]] )

In [12]: A * B                       # Elementweises Produkt
Out[12]:
array([[2, 0],
       [0, 4]])

In [13]: A @ B                       # Matrix Produkt seit Python 3.5
Out[13]:
array([[5, 4],
       [3, 4]])

In [14]: A.dot(B)                    # Altes Matrix "dot" Produkt
Out[14]:
array([[5, 4],
       [3, 4]])

12.1.3. Einfache NumPy-Array Funktionen

Einfache NumPy-Array Funktion sind:

In [15]: rg = np.random.default_rng()     # erzeuge einen Zufallszahlen Generator

In [16]: a = rg.random((2,3))

In [17]: a
Out[17]:
array([[0.1798896 , 0.11681055, 0.93822687],
       [0.2420247 , 0.53870043, 0.34058512]])

In [18]: a.sum()                       # Summe aller Array Elemente
Out[18]: 2.356237274510712

In [19]: a.min()                       # Minimum
Out[19]: 0.11681055455275102

In [20]: a.max()                       # Maximum
Out[20]: 0.9382268744684458

In [21]: np.max(a)                     # Alternative Schreibweise
Out[21]: 0.9382268744684458

In [22]: np.sqrt(a)
Out[22]:
array([[0.42413394, 0.34177559, 0.96862112],
       [0.49196005, 0.73396214, 0.58359671]])

In [23]: np.exp(a)
Out[23]:
array([[1.1970852 , 1.12390649, 2.55544627],
       [1.27382565, 1.71377823, 1.4057699 ]])

12.1.4. Array Manipulation

Typische NumPy-Array Manipulationen sind:

In [1]: import numpy as np

In [2]: a = np.array( [[1.1 , 1.9, 2.5],     # beliebiger Array
   ...:                [3.2, 6.7, 1.4 ]])

In [3]: a.shape                              # 2D Array: 2 Zeilen, 3 Spalten
Out[3]: (2, 3)

In [4]: b = np.floor(a)                      # (ab)runden

In [5]: b
Out[5]:
array([[1., 1., 2.],
       [3., 6., 1.]])

In [6]: b.ravel()                            # 1D Array "flatten"
Out[6]: array([1., 1., 2., 3., 6., 1.])

In [7]: b.reshape(3,2)                       # Neue "Shape": 3 Zeilen, 2 Spalten
Out[7]:
array([[1., 1.],
       [2., 3.],
       [6., 1.]])

In [8]: b.T                                  # Transponierte von b
Out[8]:
array([[1., 3.],
       [1., 6.],
       [2., 1.]])

12.1.5. Zeiger und Kopien

NumPy-Arrays verhalten sich gleich wie veränderbare Datentypen z.B. Listen:

In [1]: import numpy as np

In [2]: a = np.array( [2, 4, 7] ) # beliebiger Array

In [3]: b = a                     # kein neues Objekt erzeugt

In [4]: b is a                    # gleiches Objekt = Zeiger
Out[4]: True

In [5]: b[0] = 5                  # Modifikation von b ...

In [6]: a                         # ... aendert auch a!
Out[6]: array([5, 4, 7])

In [7]: c = a.copy()              # "Deep Copy"

In [8]: c is a                    # unterschiedliche Objekte
Out[8]: False

In [9]: c[0] = 9

In [10]: a                        # Modifikation von a ...
Out[10]: array([5, 4, 7])

In [11]: c                        # ... aendert c nicht!
Out[11]: array([9, 4, 7])

12.1.6. Lineare Algebra

NumPy enthält eine Vielzahl von Funktionen für die Lineare Algebra:

In [1]: import numpy as np

In [2]: A = np.array([[1.0, 2.0], [3.0, 4.0]])   # 2x2 Matrix

In [3]: print(A)
[[1. 2.]
 [3. 4.]]

In [4]: A.T                                       # Transponierte
Out[4]:
array([[1., 3.],
       [2., 4.]])

In [5]: np.linalg.inv(A)                          # Inverse
Out[5]:
array([[-2. ,  1. ],
       [ 1.5, -0.5]])

In [6]: I = np.eye(2)         # 2x2 Einheitsmatrix; "eye" fuer "I"

In [7]: I
Out[7]:
array([[1., 0.],
       [0., 1.]])

In [8]: R = np.array([[0.0, -1.0], [1.0, 0.0]])   # 2x2 Matrix

In [9]: R @ R                                     # Matrix Produkt
Out[9]:
array([[-1.,  0.],
       [ 0., -1.]])

In [10]: np.trace(I)                              # Spur der Matrix
Out[10]: 2.0

In [11]: y = np.array([[5.], [7.]])               # 2x1 Vektor

In [12]: y
Out[12]:
array([[5.],
       [7.]])


In [13]: x = np.linalg.solve(A, y)                # x = A.y (lin. Gleichungssyst.)

In [14]: x                                        # Loesungsvektor 2x1
Out[14]:
array([[-3.],
       [ 4.]])


In [15]: np.linalg.eig(A)                         # Eigenwertanalyse
Out[15]:
(array([-0.37228132,  5.37228132]),
 array([[-0.82456484, -0.41597356],
        [ 0.56576746, -0.90937671]]))

12.1.7. Beispiel

Gegeben ist folgendes Beispiel aus der Mechanik zum Thema Kräftegleichgewicht.

_images/exa_numpy.png

Gesucht ist die Größe der Kraft F im Seil und der Winkel \alpha. Von der Mechanik wissen wir dass die Summe der Kraft null ergeben muss. Der Python Code zur Lösung des Beispiels mit NumPy lautet (siehe Beispiel beispiel_numpy.py):

"""
-----------------------------
Beispiel Kraeftegleichgewicht 
-----------------------------
Author : D.H.Pahr
Datum  : 12.08.2020
-----------------------------
"""

import numpy as np 

print(__doc__)

# gegeben: Kraftvektoren
W = np.array( [0.,-80.] )
T = np.array( [40.,0.] )

print("Ergebnis")
print("~~~~~~~~")

# gesucht: F aus Gleichgewicht F+W+T=0
F = -W - T
print(f"F1    = {F[0]} N")
print(f"F2    = {F[1]} N")

# Winkel aus Skalarprodukt: W.(-F) = |W| |-F| cos(alpha)
Wn    = np.linalg.norm(W)
Fn    = np.linalg.norm(-F)
dotWF = np.dot(W,-F)
alpha = np.arccos( dotWF/Wn/Fn ) * 180./np.pi   # rad --> deg!
print(f"alpha = {alpha:.2f} °")

mit der Ausgabe:

-----------------------------
Beispiel Kraeftegleichgewicht
-----------------------------
Author : D.H.Pahr
Datum  : 12.08.2020
-----------------------------

Ergebnis
~~~~~~~~
F1    = -40.0 N
F2    = 80.0 N
alpha = 26.57 °

12.2. Matplotlib

Das Modul Matplotlib bietet vielseitige Plot-Funktionalitäten. Beispielsweise wurden die Plots in Abbildung Matplotlib Beispiele damit erstellt.

_images/matplotlib_overview.png

Matplotlib Beispiele

Für die Erstellung eines Plots verwenden wir das Untermodul pyplot welches Matlab ähnlich aufgebaut ist mittels des Imports:

import matplotlib.pyplot as plt

Einen einfachen Linienplot kann man erzeugen mit:

In [2]: plt.plot([-1, -4.5, 16, 23, 15, 59])
Out[2]: [<matplotlib.lines.Line2D at 0x2c076b5f848>]

und der Plot wir in Spyder rechts oben dargestellt.

_images/matplotlib_plot1.png

Es gibt eine Vielzahl von Möglichkeiten Plots zu erzeugen. Die wichtigsten sind im folgenden Beispiel zusammengestellt (siehe Beispiek matplotlib_plot2.py).

import matplotlib.pyplot as plt

# Erzeugung von Daten
tage = list(range(1,9))
celsius_min = [19.6, 24.1, 26.7, 28.3, 27.5, 30.5, 32.8, 33.1]
celsius_max = [24.8, 28.9, 31.3, 33.0, 34.9, 35.6, 38.4, 39.2]

# Achsenbeschriftung
plt.xlabel('Tag')
plt.ylabel('Grad Celsius')

# Plots erstellen  
plt.plot(tage, celsius_min, "og", label="Min") # Daten, 'o'..Kreis, 'g'..gruen
plt.plot(tage, celsius_min, "g--")             # Linie, '--'..strichliert
plt.plot(tage, celsius_max, "b")
plt.plot(tage, celsius_max, "^b", label="Max")

# Optional: Min/Max Werte der Achsen veraendern
xmin, xmax = 0, 10
ymin, ymax = 0, 42
plt.axis([xmin, xmax, ymin, ymax])

# Optional: Legende einfuegen, label in plt.plot Funktion 
plt.legend(loc='lower right')                  # Position der Legende 

# Zeige Plot (nicht notwendig in Sypder)
plt.show()
_images/matplotlib_plot2.png

Eine umfangreichere Beschreibung der Funktionalität von Matplotlib findet sich unter: https://www.python-kurs.eu/matplotlib.php

12.3. Scipy

SciPy “Scientific Python” wird oft im gleichen Atemzug wie NumPy genannt. SciPy erweitert die Leistungsfähigkeit von NumPy.

Ein Beispiel ist die Interpolation von Datenpunkten (siehe Beispiel scipy_interpolate.py):

"""
SciPy Beispiel 1D Interpolation
"""

import numpy as np

from scipy.interpolate import interp1d

# xy Punktwerte z.B Messwerte 
x = np.linspace(0, 10, num=11, endpoint=True)
y = np.array( [ 1.,0.99,0.90,0.54,-0.21,-0.93,-0.65,0.67,0.68,-0.91,0.12] )

print(y)

# Interpolation
f = interp1d(x, y)
f2 = interp1d(x, y, kind='cubic')

# Ausgabe 
xnew = np.linspace(0, 10, num=41, endpoint=True)
import matplotlib.pyplot as plt
plt.plot(x, y, 'o', xnew, f(xnew), '-', xnew, f2(xnew), '--')
plt.legend(['Messdaten', 'Linear', 'Kubisch'], loc='best')
plt.show()

Im folgenden Bild sieht man die Datenwerte, sowie eine linear und kubische Interpolation.

_images/scipy.png

Ein weiteres Beispiel ist die numerische Integration. Das folgende Integral

I(a,b) = \int_0^1 (a\,x^2 + b) dx

kann numerisch gelöst werden mittels (siehe Beispiel scipy_integrate.py):

"""
SciPy Beispiel Numerische Integration
"""

from scipy.integrate import quad

# zu integrierende Funktion 
def integrand(x, a, b):
    return a*x**2 + b

# Berechnung des Integrals
a = 2
b = 1
Integral, Fehler = quad(integrand, 0, 1, args=(a,b))  # Fortran QUADPACK

print("Ergebnis =", Integral)

Die Ausgabe des Python Skriptes lautet

Ergebnis = 1.6666666666666667

12.4. Jupyter

Jupyter, genauer gesagt Jupyter Notebooks,

  • sind Webdokumente für die interaktive Entwicklung und Präsentation von wissenschaftlichen Projekten welche
  • Code und Ausgabe in ein Dokument integrieren und
  • Visualisierungen, narrativen Text, mathematische Gleichungen und andere Inhalte kombinieren.

12.4.1. Start von Jupyter

Anaconda fügt unter Windows dem Startmenü Jupyter hinzu. Das Starten dieser App öffnet eine neue Registerkarte im Standard-Webbrowser.

_images/jupyter1.png

localhost deutet darauf dass es sich um eine lokale Seite und keine Webseite handelt.

Mittels Klick auf New und Python 3 erzeugt man ein neues Notebook.

_images/jupyter2.png

Es wird automatisch ein File Untitled.ipynb im Arbeitsverzeichnis (Verzeichnis welches die Registerkarte im Standard-Webbrowser anzeigt) gespeichert. Mit Save as .. kann man dieses File umbenennen.

12.4.2. Notebook Interface

Das Notebook Interface ist ein erweiterter Texteditor welcher neben formatierten Text auch ausführbaren Code enthalten kann.

_images/jupyter3.png

Diese einzelnen Text- oder Code Blöcke (“In [..]”) werden als Cells bezeichnet. Die “Computational Engine” (hier der Python Interpreter) welche Code verarbeitet wird als Kernel bezeichnet.

Gibt man in die erste Code Cell folgendes ein:

print("Hello Jupyter")

ein und führt diese mit dem Run Knopf oder Ctrl + Enter Shortcut aus, erhält man wie in der Abbildung gezeigt eine Ausgabe.

Wichtige Befehle bzw. Shortcuts eines Notebooks sind:

  • Eine neue Zelle erzeugt man mit dem Knopf + oder A
  • Alle Tastatur Shortcuts erhält man durch klicken auf den Tastatur Knopf (rechts oben).
  • Zwischen Edit und Command Mode wechselt man mit Esc (blauer Zellrahmen links) und Enter (grüner Zellrahmen).

Im Command Mode (blauer Zellrahmen links) kann man:

  • mit Rauf und Runter Tasten zwischen Zellen wechseln
  • mit A oder B darunter oder darüber Zellen erzeugen
  • M wechselt zu einer Markdown (Text) Zelle.
  • Y wechselt zu einer Code Zelle.
  • zweimal D löscht die aktive Zelle.
  • Z macht das Löschen rückgängig
  • mit Shift + halten und Rauf / Runter Tasten kann man mehrere Zellen markieren, Shift + M fügt markierte Zellen zusammen

12.4.3. Markdown

Im Edit Mode lässt sich einfach ein formatierter Text erzeugen. Gibt man in eine Markdown Zelle folgenden Text ein:

# Überschrift 1
## Überschrift 2
Normaler Text mit **fett** und *italic* Text.

Ein neuer Paragraph wird durch eine leere Zeile erzeugt.
* Manchmal braucht man Aufzählungen
* Mit mehreren Punkten.

oder
1. nummerierte Listen
2. wie hier dargestellt.

[Es ist möglich Hyperlinks einzufügen](https://www.example.com)

Inline code wird mittels einfacher Hochkomma erzeugt z.B. `foo()`, und Code Blöcke mit dreifachen Hochkomma:
```
bar()
```

Auch Bilder sind einfach einzufügen:

![Titel](code.png)

Formel kann man mittels $\LaTeX$ Syntax einfügen:

$$e^{i\pi} + 1 = 0$$

Tabellen einfach so:

| Das  | ist     |
|------|---------|
| eine | Tabelle |

erhält man nach ausführen der Zelle mit Ctrl + Enter folgendes Ergebnis:

_images/jupyter4.png

und kann damit schön formatierte technische Berichte erzeugen.

12.4.4. Kernel

Hinter jedem Notebook läuft ein Kernel, bei uns Python 3. Beispielsweise kann man in einer Zelle folgendes definieren:

import numpy as np
def wurzel(x):
    return x ** 0.5

und danach diese Funktion verwenden d.h.:

_images/jupyter5.png

Dabei gibt es folgendes zu beachten:

  • Ändert man Werte in einer Zelle, muss man diese mit Ctrl + Enter neu berechnen.
  • Möchte man alle Zellen neu berechnen, muss man Restart & Run All ausführen!

12.5. Jupyter Beispiel

Das Beispiel findet sich unter Jupyter_Beispiel.ipynb und demonstriert eine ingenieurwissenschaftliche Anwendung aus dem Bereich der Physik.

Es wird dabei die Flugbahn eines Projektils untersucht und gleichzeitig ein Berechnungsbericht erstellt. Das folgende Bild zeigt ein Ergebnis dieser Untersuchungen.

_images/projektil.png

12.6. Übungsbeispiele

Aufgabe 12.1

In dieser Aufgabe soll die Kraft-Verschiebungs-Kurve einer Probe aus dem Bereich des Biomedical-Engineerings mit Hilfe von Python ausgewertet werden. Im anschließenden Bild sehen Sie die getestete Probe, sowie die zugehörige Kraft-Verschiebungs-Kurve, die mit einer Materialprüfmaschine gemessen wurde.

_images/Aufgabe_12_1.png

Die Daten für die Verschiebung in mm und Kraft in Newton sind als Listen gegeben:

# Verschiebung in mm
verschiebung = [   0.        , 0.09810706, 0.19972906, 0.30051106, 0.40117306,
                   0.50129506, 0.60165706, 0.70189806, 0.80202006, 0.90190206,
                   1.00214806, 1.10196806, 1.20214806, 1.30184806, 1.40196806,
                   1.50238806, 1.60227806]

# Kraft in Newton
kraft = [    10.    ,  84.3959, 167.649 , 238.241 , 297.654 , 350.267 ,
             397.334 , 440.565 , 479.436 , 511.907 , 543.733 , 574.285 ,
             601.333 , 618.475 , 585.185 , 510.965 , 498.479 ]

Ziel ist es, die Belastung in kg über die Verschiebung grafisch darzustellen, sowie die maximale Belastung und die Belastung der Probe bei einer Verschiebung von 0.35 mm zu ermitteln.

Gehen Sie dafür wie folgt vor:

  1. Wandeln Sie die Listen verschiebung und kraft in NumPy-Arrays um.

  2. Ziehen Sie die Vorlast von 10 Newton von allen Einträgen des kraft arrays ab. Rechnen Sie anschließend die Belastung von Newton in kg um, indem Sie alle Einträge mit 9.81 (m/s^2) dividieren. Das kraft array sollte dann wie folgt aussehen:

    In [1]: print(kraft_array_kg)
    [ 0.          7.58367992 16.07023445 23.26615698 29.32252803 34.68572885
      39.48358818 43.89041794 47.85280326 51.16279307 54.40703364 57.52140673
      60.27859327 62.02599388 58.63251784 51.0667686  49.79398573]
    
  3. Stellen Sie den Verlauf der Belastung in kg über die Verschiebung in mm dar. Verwenden Sie dafür die plot Funktion der Bibliothek matplotlib (siehe Kapitel 12.2. im Skriptum). Ihr Ergebnis sollte dann wie folgt aussehen:

_images/Aufgabe_12_1_results.png
  1. Berechnen Sie abschließend die maximale Belastung der Probe in kg sowie die Belastung bei einer Verschiebung von 0.35 mm. Um die Kraft bei einer bestimmten Verschiebung zu berechnen, verwenden Sie interp1d von Scipy (siehe Kapitel 12.3. Skriptum). Geben Sie dann das Ergebnis per print Befehl aus. Die Ausgabe sollte dann in etwa wie folgt aussehen:

    Maximale Belastung: 62.03 kg
    Belastung bei 0.35mm: 26.24 kg
    

12.7. Übungsbeispiel für Kolloquium

Das folgende Beispiel ist aufbauend und kapitelübergreifend. Es soll Ihnen beim Üben bzw. bei der Vorbereitung für das Kolloquium helfen. Es ist allerdings nicht repräsentativ für Art, Umfang oder Schwierigkeitsgrad der Beispiele des Kolloquiums!

Aufgabe K.1

  1. Schreiben Sie eine Klasse Haus. Der Konstruktor bekommt die Argumente Adresse (string), Hoehe (float-Zahl) und Etagenanzahl (integer-Zahl) übergeben und soll sie als Klassenattribute initialiseren. Die Adresse soll als privates Attribut gespeichert werden.
  2. Schreiben Sie eine get-Methode, mit der die Adresse abgefragt werden kann.
  3. Die Klasse soll eine überladene print-Funktion enthalten, sodass mittels print die Adresse, die Höhe und die Etagenanzahl ausgegeben werden.
  4. Ergänzen Sie Ihre Klasse Haus durch ein statisches Attribut Anzahl_Haus. Anzahl_Haus soll immer die Anzahl, der jeweils bisher im gesamten Skript erzeugten Instanzen der Klasse zählen.
  5. Überladen Sie zusätzlich den kleiner-Vergleichsoperator (__lt__). Ein Haus soll als kleiner als ein zweites Haus angesehen werden, wenn es niedriger (Höhe geringer) ist.

Überprüfen Sie Ihre Implementierung mit geeignetem Input im Abschnitt ‘main’. z.B.:

In [1]: Haus1 = Haus("Kirchengasse 3",16.27,5)
In [2]: print(Haus1)
Adresse: Kirchengasse 3, Hoehe: 16.27, Etagenanzahl: 5
In [3]: print(Haus1.Get_Adresse())
Kirchengasse 3
In [4]: print(Haus1.Anzahl_Haus)
1
In [5]: Haus2 = Haus("Kellergasse 1",18.3,6)
In [6]: print(Haus1 < Haus2)
True
In [7]: print(Haus1.Anzahl_Haus)
2

Aufgabe K.2

  1. Schreiben Sie eine Klasse Wolkenkratzer, die von der Klasse Haus abgeleitet wird. Sie soll zusätzlich zu den Attributen von Haus noch das Attribut Name (string) haben. Wolkenkratzer sind meistens über ihren Namen und nicht über ihre Adresse bekannt (z.B. DC-Tower, Donauturm, Empire-state-building,...).
  2. Überladen Sie für die Klasse Wolkenkratzer die print-Funktion, sodass ein String, der alle Attribute von Wolkenkratzer enthält, mit print ausgegeben werden kann.
  3. Ergänzen Sie Ihre Klasse Wolkenkratzer durch ein statisches Attribut Anzahl_Wolkenkratzer. Anzahl_Wolkenkratzer soll immer die Anzahl, der jeweils bisher im gesamten Skript erzeugten Instanzen der Klasse zählen.

z.B.:

In [1]: Wolkenkratzer1 = Wolkenkratzer("Donau-City-Strasse 7",220.3,60,"DC-Tower")
In [2]: print(Wolkenkratzer1)
Adresse: Donau-City-Strasse 7, Hoehe: 220.3, Etagenanzahl: 60, Name: DC-Tower

Aufgabe K.3

Schreiben Sie in einem neuen python-File eine Funktion Read_Haeuser (soll keine Klassen-Methode sein!). Dieser Funktion wird der Name einer Textdatei übergeben, die zeilenweise mehrere Häuser enthält. Eine Beispieldatei “Input_Haeuser.txt” ist in TUWEL verfügbar:

Parkring 18, 18.2, 5
Donau-City-Strasse 7, 220.3, 60, DC-Tower
Handelskai 94-96, 171.5, 50, Millenium-Tower
Kirchengasse 3, 16.27, 5
  1. Importieren Sie Ihre Klassen Haus und Wolkenkratzer.
  2. Die Funktion soll zunächst mit Hilfe einer Ausnahmebehandlung überprüfen, ob das File geöffnet werden kann:
  • Falls nein, soll die Funktion die Art des Fehlers als string zurück geben.
  • Falls ja, soll die Textdatei eingelesen werden.
  1. Die Textdatei enthält mehrere Zeilen, wobei jede Zeile ein Haus bzw. einen Wolkenkratzer definiert:
  • Ein Haus wird in der Textdatei wie folgt definiert: Adresse, Höhe, Etagenanzahl
  • Ein Wolkenkratzer wird in der Textdatei wie folgt definiert: Adresse, Höhe, Etagenanzahl, Name

Lesen Sie das File ein und erstellen Sie eine Liste aus Haus- und Wolkenkratzer-Objekten, wobei jede Zeile des Files zur Initialisierung eines Haus- oder eines Wolkenkratzer-Objektes verwendet werden soll.

  1. Danach soll diese Hausliste mit Hilfe des überladenen kleiner-Operators aufsteigend sortiert werden, d.h. nach der Höhe sortiert werden. Die sortierte Liste der Häuser soll zurück gegeben werden.

Hinweis

  • Die Python-Funktionen sort und sorted verwenden den kleiner-Operator zum Sortieren.
  • Damit der überladene print-Operator zum Ausgeben der Liste von Häusern und Wolkenkratzern verwendet wird, muss eine Schleife über die Liste verwendet werden.
  • Sie können auch testen, ob Ihr Skript noch funktioniert wenn Sie versuchen eine nicht existierende Datei oder die Datei “Input_Haueser2.txt” aus TUWEL einzulesen.

Beispiel für Nutzung der Funktion und Ausgabe:

In [1]: Gebaeude_Liste = Read_Haeuser("Input_Haeuser.txt")
In [2]: for i in Gebaeude_Liste:
   ...:     print(i)
Adresse: Kirchengasse 3, Hoehe: 16.27, Etagenanzahl: 5
Adresse: Parkring 18, Hoehe: 18.2, Etagenanzahl: 5
Adresse: Handelskai 94-96, Hoehe: 171.5, Etagenanzahl: 50, Name: Millenium-Tower
Adresse: Donau-City-Strasse 7, Hoehe: 220.3, Etagenanzahl: 60, Name: DC-Tower