Home | Lehre | Videos | Texte | Vorträge | Software | Person | Impressum, Datenschutzerklärung | Blog RSS

Stand: 2024-05-05
weitgehend formuliert von Claude 3 Opus

Umstieg von C auf Python, Teil 2

Globale und lokale Variablen in Python-Funktionen

In Python gibt es zwei Arten von Variablen: globale und lokale Variablen. Wenn Sie bereits Erfahrung mit C haben, sind Ihnen die Konzepte wahrscheinlich vertraut. Dennoch gibt es einige Unterschiede, die es zu beachten gilt.

Lokale Variablen

Lokale Variablen werden innerhalb einer Funktion definiert und sind nur innerhalb dieser Funktion sichtbar. Sie können außerhalb der Funktion nicht zugegriffen werden. Hier ist ein Beispiel:

def meine_funktion():
    x = 10  # Lokale Variable
    print(x)

meine_funktion()  # Ausgabe: 10
print(x)  # Fehler: NameError: name 'x' is not defined

Globale Variablen

Globale Variablen werden außerhalb von Funktionen definiert und sind von überall im Programm aus zugänglich, auch innerhalb von Funktionen. Hier ist ein Beispiel:

y = 20  # Globale Variable

def meine_funktion():
    print(y)

meine_funktion()  # Ausgabe: 20
print(y)  # Ausgabe: 20

Zugriff auf globale Variablen innerhalb einer Funktion

Wenn Sie innerhalb einer Funktion auf eine globale Variable zugreifen und ihren Wert ändern möchten, müssen Sie das Schlüsselwort global verwenden. Andernfalls erstellt Python eine neue lokale Variable mit demselben Namen. Hier ist ein Beispiel:

z = 30  # Globale Variable

def meine_funktion():
    global z
    z = 40  # Ändert den Wert der globalen Variable

meine_funktion()
print(z)  # Ausgabe: 40

Beste Praktiken

Es ist im Allgemeinen eine gute Praxis, die Verwendung von globalen Variablen zu minimieren und stattdessen Parameter und Rückgabewerte zu verwenden, um Daten zwischen Funktionen auszutauschen. Dies verbessert die Lesbarkeit, Wartbarkeit und Testbarkeit Ihres Codes.

Ich hoffe, diese Erklärung hat Ihnen geholfen, globale und lokale Variablen in Python besser zu verstehen. Bei weiteren Fragen zögern Sie nicht, nachzufragen!

Listen

In Python sind Listen ein fundamentaler Datentyp, der verwendet wird, um mehrere Elemente in einer geordneten Reihenfolge zu speichern. Listen in Python ähneln Arrays in C, bieten jedoch mehr Flexibilität und eingebaute Funktionalitäten.

Im Gegensatz zu Arrays in C müssen Listen in Python nicht mit einer festen Größe initialisiert werden. Sie können zur Laufzeit wachsen oder schrumpfen, indem Elemente hinzugefügt oder entfernt werden. Außerdem können Listen Elemente unterschiedlicher Datentypen enthalten, während Arrays in C meist nur Elemente desselben Datentyps speichern.

Deklaration und Verwendung von Listen

Eine Liste in Python wird mit eckigen Klammern [] deklariert und kann Elemente verschiedener Datentypen enthalten. Hier ist ein Beispiel:

my_list = [1, 2, 'drei', 4.0, True]

Auf die Elemente einer Liste kann über ihren Index zugegriffen werden, wobei der Index bei 0 beginnt:

print(my_list[0])  # Ausgabe: 1
print(my_list[2])  # Ausgabe: 'drei'

Iteration über Listen mittels for

In Python gibt es verschiedene Möglichkeiten, über Listen zu iterieren. Eine davon ist die Verwendung der schon bekannten for-Schleife mit einer Liste statt mit range. Hier ist ein einfaches Beispiel:

zahlen = [1, 2, 3, 4, 5]

for zahl in zahlen:
    print(zahl)

Ausgabe:

1
2
3
4
5

Methoden von Listen und Funktionen für Listen

Listen in Python bieten eine Vielzahl von nützlichen Methoden:

Die Anzahl an Elementen einer Liste zahlen erhält man mit len(zahlen), die Summe der Elemente mit sum(zahlen). Diese beiden sind keine Methoden wie append usw. von oben, sondern Funktionen; hier steht also nicht zahlen.tu_etwas(), sondern tu_etwas(zahlen). (Später im Semester mehr dazu.)

Addition und Multiplikation von Listen

Listen lassen sich mit dem +-Operator addieren, um eine neue Liste zu erhalten, die die Elemente beider Listen enthält. Hier ist ein Beispiel:

liste1 = [1, 2, 3]
liste2 = [4, 5, 6]
liste3 = liste1 + liste2
print(liste3)  # Ausgabe: [1, 2, 3, 4, 5, 6]

Listen lassen sich auch mit dem *-Operator multiplizieren, um eine neue Liste zu erhalten, die die Elemente der ursprünglichen Liste mehrfach enthält. Hier ist ein Beispiel:

liste = [1, 2, 3]
liste_mehrfach = liste * 3
print(liste_mehrfach)  # Ausgabe: [1, 2, 3, 1, 2, 3, 1, 2, 3]

Beachte, dass sowohl die Addition als auch die Multiplikation von Listen neue Listen erzeugen und die ursprünglichen Listen nicht verändern.

Negative Indizes

Python unterstützt auch negative Indizes, um auf Elemente vom Ende der Liste aus zuzugreifen. Der Index -1 bezieht sich auf das letzte Element, -2 auf das vorletzte Element usw.

my_list = [1, 2, 3, 4, 5]
print(my_list[-1])  # Ausgabe: 5
print(my_list[-3])  # Ausgabe: 3

Slices

Slices ermöglichen es, Teilbereiche einer Liste zu extrahieren. Die Syntax lautet list[start:end:step], wobei start der Startindex (inklusiv), end der Endindex (exklusiv) und step die Schrittweite ist.

my_list = [1, 2, 3, 4, 5]
print(my_list[1:4])    # Ausgabe: [2, 3, 4]
print(my_list[::2])    # Ausgabe: [1, 3, 5]
print(my_list[1:-1])   # Ausgabe: [2, 3, 4]
print(my_list[::-1])   # Ausgabe: [5, 4, 3, 2, 1]

Listen als Funktionsparameter

Listen können als Parameter an Funktionen übergeben werden. In Python werden Listen (wie auch alles andere) als Referenz übergeben, also ähnlich wie man in C mit Pointern arbeitet. Das bedeutet, dass Änderungen an der Liste innerhalb der Funktion auch außerhalb der Funktion sichtbar sind.

Hier ist ein Beispiel für eine Funktion, die eine Liste als Parameter erhält und ein Element hinzufügt:

def add_item(my_list: list, item: any) -> None:
    my_list.append(item)

In diesem Beispiel verwenden wir Type Hints, um anzuzeigen, dass my_list eine Liste und item ein beliebiger Datentyp sein kann. Die Funktion gibt None zurück.

Type Hints für Listen

Type Hints können verwendet werden, um den Typ von Listenelementen anzugeben. Hier ist ein Beispiel:

from typing import List

def beispiel_funktion(namen: ist[str]) -> None:
    for name in namen:
        print(name)

Fallunterscheidung mittels Mustern

Seit Neuerem kennt Python das Statement match. Es ist eine elegante Alternative zum switch-Statement in C. Mit match lassen sich verschiedene Fälle (Cases) basierend auf dem Wert eines Ausdrucks unterscheiden und der entsprechende Code ausführen.

In C ist switch auf Integer-Werte und Konstanten beschränkt, während match in Python mit verschiedenen Datentypen und komplexen Mustern arbeiten kann. Die case-Klauseln in Python benötigen kein explizites break, um ein Durchfallen zu verhindern. Jeder case wird getrennt behandelt.

Python erlaubt die Verwendung eines Wildcard-Falls (case _), der ausgeführt wird, wenn kein anderes Muster zutrifft. In C gibt es dafür das optionale default.

Beispiele

Hier ist ein einfaches Beispiel für die Verwendung von match in Python:

def describe_color(color):
    match color:
        case 'red':
            return 'Rot wie eine Tomate'
        case 'green':
            return 'Grün wie Gras'
        case 'blue':
            return 'Blau wie der Himmel'
        case _:
            return 'Unbekannte Farbe'

print(describe_color('red'))    # Ausgabe: Rot wie eine Tomate
print(describe_color('purple')) # Ausgabe: Unbekannte Farbe

In diesem Beispiel wird der Wert von color mit den verschiedenen Mustern verglichen und der entsprechende String zurückgegeben.

Hier ein komplizierteres Beispiel; beachte, dass anders als in C kein break verwendet wird:

def calculate_price(product, quantity, discount):
    match product:
        case 'apple' if quantity > 10:
            price = 0.5 * quantity
        case 'apple':
            price = 0.8 * quantity
        case 'banana' if discount:
            price = 0.6 * quantity
        case 'banana':
            price = 1.0 * quantity
        case _:
            price = 0

    return price

# Beispielaufrufe
print(calculate_price('apple', 5, False))    # Ausgabe: 4.0
print(calculate_price('apple', 15, False))   # Ausgabe: 7.5
print(calculate_price('banana', 3, True))    # Ausgabe: 1.8
print(calculate_price('banana', 3, False))   # Ausgabe: 3.0
print(calculate_price('orange', 5, False))   # Ausgabe: 0

In diesem Beispiel haben wir eine Funktion calculate_price, die den Preis basierend auf dem Produkt, der Menge und einem optionalen Rabatt berechnet. Wir verwenden das match-Statement, um verschiedene Fälle abzudecken:

Die Verwendung von if-Bedingungen innerhalb der case-Klauseln ermöglicht es uns, zusätzliche Bedingungen zu überprüfen, bevor ein bestimmter Fall ausgeführt wird. Soll ein case mehrere Werte abdecken, kann man diese mit | zusammenfassen: case 23 | 42 In diesem Fall bedeutet der vertikale Strich nicht das bitweise Oder!

Enum in Python

Python bietet mit dem enum-Modul eine Möglichkeit, symbolische Namen für Konstanten zu definieren, ähnlich wie das enum in C. Enums in Python sind jedoch mächtiger und bieten zusätzliche Funktionalitäten.

Definition eines Enums

Ein Enum in Python wird durch Ableiten von der Klasse Enum definiert. (Klassen und Ableitungen kommen später noch ausführlich.) Hier ist ein Beispiel:

from enum import Enum

class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

In diesem Beispiel wird ein Enum namens Color definiert, das drei Konstanten (RED, GREEN und BLUE) enthält. Jeder Konstante wird ein eindeutiger Wert zugewiesen.

Auf die Konstanten eines Enums kann über den Enum-Namen und den Konstantennamen zugegriffen werden:

print(Color.RED)  # Output: Color.RED
print(Color.RED.value)  # Output: 1

Matching mit Enums

Mit Enums kann match verwendet werden, um basierend auf dem Wert einer Enum-Konstante verschiedene Aktionen auszuführen:

def print_color(color):
    match color:
        case Color.RED:
            print('The color is red')
        case Color.GREEN:
            print('The color is green')
        case Color.BLUE:
            print('The color is blue')

print_color(Color.RED)  # Output: The color is red

Textdateien in Python

In Python ist das Lesen und Schreiben von Textdateien ein häufig verwendetes Konzept. Ähnlich wie in C verwendet man dazu Dateiströme, allerdings ist die Syntax in Python einfacher und intuitiver.

Öffnen und Schließen von Dateien

Um eine Datei in Python zu öffnen, verwendet man die Funktion open(). Sie erwartet als Parameter den Dateinamen und optional den Modus, in dem die Datei geöffnet werden soll (z.B. r für Lesen, w für Schreiben).

file = open('datei.txt', 'r')

Gibt man hier nur den Namen der Datei an, muss sie typischerweise direkt neben der Python-Datei liegen. Es sind aber auch absolute und relative Pfadangaben möglich. Vorsicht damit unter Windows: Dies benutzt den Rückwärtsstrich \ als Trenner, der aber in Zeichenketten Sonderbedeutungen wie \n = neue Zeile und \t = Tabulator besitzt. Eine Zeichenkette wie 'C:\irgendwo\test.txt' wird deshalb nicht akzeptiert. Stattdessen kann man wie in C schreiben: 'C:\\irgendwo\\test.txt' oder Python-typisch ein r davorsetzen, um die Sonderbedeutungen des \ abzuschalten: r'C:\irgendwo\test.txt'.

Nach dem Öffnen der Datei sollte sie auch wieder geschlossen werden, um Ressourcen freizugeben und anderen Programmen bzw. Nutzern wieder den Zugriff auf die Datei zu gestatten. Dies geschieht mit der Methode close().

file.close()

Lesen aus Dateien

Zum Lesen von Daten aus einer Datei stehen verschiedene Methoden zur Verfügung:

Beispiel:

file = open('datei.txt', 'r')
content = file.read()
print(content)
file.close()

Schreiben in Dateien

Zum Schreiben von Daten in eine Datei verwendet man die Methode write(). Sie erwartet einen String als Parameter, der in die Datei geschrieben wird.

Beispiel:

file = open('datei.txt', 'w')
file.write('Hallo, Welt!')
file.close()

Das with-Statement

Um sicherzustellen, dass eine Datei immer ordnungsgemäß geschlossen wird, auch im Falle einer Exception (mehr dazu später im Semester), bietet Python das with-Statement. Es sorgt automatisch für das Schließen der Datei, sobald der with-Block verlassen wird.

Beispiel:

with open('datei.txt', 'r') as file:
    content = file.read()
    print(content)

Innerhalb des with-Blocks kann die Datei wie gewohnt verwendet werden. Nach Verlassen des Blocks wird die Datei automatisch geschlossen, ohne dass explizit close() aufgerufen werden muss.

UTF-8-Codierung

Von C ist man gewohnt, dass Textdateien normalerweise mit ASCII oder einer anderen Codepage gespeichert werden. In Python ist das anders: Hier wird für Textdateien standardmäßig die Kodierung UTF-8 verwendet, außer derzeit noch unter Windows.

UTF-8 ist eine Kodierung für Unicode-Zeichen. Es kann damit eine große Anzahl an Zeichen aus verschiedenen Sprachen dargestellt werden, darunter auch Sonderzeichen und Emojis. UTF-8 ist abwärtskompatibel zu ASCII: Die ersten 128 Zeichen entsprechen dem ASCII-Zeichensatz.

Alte Textdateien und alte Programme können noch andere Codierungen als UTF-8 verwenden, was man daran erkennt, dass ä, €, 🔋 usw. nicht korrekt übertragen werden. Dann ist es nötig, in Python die Codierung ausdrücklich anzugeben, wie in diesem Beispiel:

file = open('datei.txt', 'r', encoding='cp1252')

Pfadmanipulationen mit Pathlib

Die Handhabung von Dateipfaden (also den Angaben, welche Datei oder welches Verzeichnis zu nutzen ist) kann schnell komplex und fehleranfällig werden, besonders wenn es um plattformübergreifende Entwicklung geht. Hier kommt pathlib ins Spiel. pathlib ist ein Modul in der Python-Standardbibliothek, das die Arbeit mit Pfaden einfacher, intuitiver und weniger fehleranfällig gestaltet.

Anwendungsbeispiele

  1. Dateien öffnen

    from pathlib import Path
    
    # Pfad erstellen
    pfad = Path('ordner/datei.txt')
    
    # Überprüfen, ob die Datei existiert
    if pfad.exists():
        # Datei öffnen und lesen
        with open(pfad, 'r') as datei:
            inhalt = datei.read()
            print(inhalt)
    else:
        print('Die Datei existiert nicht.')
  2. Pfade erstellen und zusammensetzen:

    # Pfad zum Home-Verzeichnis des Benutzers
    home = Path.home()
    
    # Pfad zu einer Datei im Downloads-Ordner
    # Der Operator / bedeutet hier das Aneinanderhängen
    file_path = home / 'Downloads' / 'example.txt'
  3. Dateien und Verzeichnisse überprüfen:

    file_path = Path('path/to/file.txt')
    
    if file_path.is_file():
        print('Es ist eine Datei.')
    elif file_path.is_dir():
        print('Es ist ein Verzeichnis.')
  4. Durch Verzeichnisse navigieren:

    directory = Path('path/to/directory')
    
    for file in directory.iterdir():
        if file.is_file() and file.suffix == '.txt':
            print(file.name)