Zahlen als Objekte
Jede Zahl in Python ist ein Objekt mit einem numerischen Typ. Dieser Typ bestimmt, welche Attribute und Methoden du über die Punktschreibweise erreichen kannst.
Die Schreibweise erzeugt einen int, die Schreibweise einen float. Die hier behandelten eingebauten numerischen Objekte sind unveränderlich. Ein Methodenaufruf wie conjugate() gibt ein Ergebnis zurück, ohne den Wert des ursprünglichen Objekts zu ändern.
Bei a = 5 bindet die Zuweisung a = a + 1 den Namen a an ein Objekt mit dem Wert 6. Unterscheide dabei Objektidentität und Namenszuweisung: Das Objekt mit dem Wert 5 hat sich nicht in 6 verwandelt.
Auf Attribute und Methoden zugreifen
Ein Attributzugriff liest einen Wert über ein benanntes Objektmitglied, ein Methodenaufruf führt eine Operation aus. Allgemein kann ein Attribut beim Zugriff auch einen Wert berechnen. Du liest ein Attribut mit object.attribute und rufst eine Methode mit object.method() auf. Die Klammern in der zweiten Form sagen Python, dass es die Methode ausführen soll.
Eine komplexe Zahl zeigt den Unterschied deutlich. Der Ausdruck c.real sind Daten, die Python bereits in c speichert, der Attributzugriff liefert diesen Realteil. Der Aufruf c.conjugate() ist Arbeit, die Python in diesem Moment ausführt, und das Ergebnis ist eine zweite komplexe Zahl, die c unverändert lässt.
# Eine komplexe Zahl erzeugen
c = 2 + 3j
# Attribut real lesen (Realteil)
print(c.real) # Ausgabe: 2.0
# Attribut imag lesen (Imaginärteil)
print(c.imag) # Ausgabe: 3.0
# Methode conjugate() fuer das Konjugat aufrufen
print(c.conjugate()) # Ausgabe: (2-3j)Den numerischen Typ bestimmen
Python wählt den numerischen Typ aus dem Literal, das du schreibst, und dieser Typ entscheidet, welche Attribute und Methoden der Wert mitbringt. Wenn du Python vor einem typspezifischen Aufruf nach der Klasse fragst, musst du nicht raten, ob diese Operation auf dem Wert überhaupt existiert.
Die Funktion type() liefert die Klasse des Werts, also ein Klassenobjekt, keinen String mit dem Typnamen. Die drei Literale unten sehen als Argument einer Funktion ähnlich aus, type() meldet für jedes davon aber eine andere Klasse.
Die Typfunktion verwenden
Unterscheide Literale und Ausdrücke: 3j ist ein imaginäres Literal, während 2 + 3j eine Addition mit einem complex-Objekt als Ergebnis ist.
# Datentypen von Zahlen anzeigen
print(type(42)) # Ausgabe: <class 'int'>
print(type(3.14)) # Ausgabe: <class 'float'>
print(type(2+3j)) # Ausgabe: <class 'complex'>| Ausdruck | Klasse, die type() meldet | Grund für die Wahl dieser Klasse |
|---|---|---|
42 | int | Das Literal hat weder Dezimalpunkt noch Exponent |
3.14 | float | Das Literal enthält einen Dezimalpunkt |
2+3j | complex | Die Addition einer Ganzzahl und des imaginären Literals 3j ergibt complex |
Die Bestandteile einer komplexen Zahl lesen
Eine komplexe Zahl hält ihre zwei Bestandteile getrennt, und Python stellt beide als Attribute bereit, statt dich sie selbst zerlegen zu lassen. Das Attribut real speichert den Realteil, das Attribut imag speichert den Koeffizienten der imaginären Einheit, und beide kommen als Floats zurück, auch bei ganzen Zahlen.
Jedes Attribut liefert einen Bestandteil der Zahl. Der Vergleich einer rein reellen Zahl, einer rein imaginären Zahl und einer gemischten Zahl zeigt, welcher Bestandteil zu welchem Attribut gehört.
Das Attribut real
Das Attribut real liefert den Realteil der Zahl. Das Lesen verändert die Zahl nie, du kannst denselben Wert also beliebig oft untersuchen.
# Beispiel fuer das Attribut real
z1 = 4 + 5j
z2 = -2 + 7j
z3 = 10 + 0j # Rein reelle Zahl
print(f"Realteil von {z1} ist {z1.real}")
print(f"Realteil von {z2} ist {z2.real}")
print(f"Realteil von {z3} ist {z3.real}")
# Ausgabe:
# Realteil von (4+5j) ist 4.0
# Realteil von (-2+7j) ist -2.0
# Realteil von (10+0j) ist 10.0Das Attribut imag
Das Attribut imag liefert den Koeffizienten von , und Python schreibt diese Einheit im Literal einer komplexen Zahl als j. Das Vorzeichen gehört zum Koeffizienten, ein abgezogener Term kommt also als negative Zahl zurück.
# Beispiel fuer das Attribut imag
z1 = 3 + 8j
z2 = 6 - 4j
z3 = 0 + 9j # Rein imaginaere Zahl
print(f"Imaginaerteil von {z1} ist {z1.imag}")
print(f"Imaginaerteil von {z2} ist {z2.imag}")
print(f"Imaginaerteil von {z3} ist {z3.imag}")
# Ausgabe:
# Imaginaerteil von (3+8j) ist 8.0
# Imaginaerteil von (6-4j) ist -4.0
# Imaginaerteil von 9j ist 9.0Das Ergebnis für z2 ist , weil der Koeffizient das Minuszeichen vor der imaginären Einheit trägt. Der Wert von z1 bleibt positiv, und die rein imaginäre Zahl z3 meldet mit dem Realteil .
Methoden für komplexe Zahlen
Komplexe Zahlen bringen eigene Methoden mit, und die Methoden unten decken die Operationen ab, die du am häufigsten brauchst. Die Methode conjugate() liefert eine komplexe Zahl, du kannst also weiter auf dem Ergebnis aufrufen, ohne den Ausgangswert zu verändern.
Die Methode conjugate
Für liefert conjugate() den Wert . Der Realteil behält seinen Wert und nur der Imaginärteil wechselt das Vorzeichen, wodurch das Konjugat das Spiegelbild der Zahl an der reellen Achse wird.
# Beispiel fuer die Methode conjugate()
z1 = 3 + 4j
z2 = -2 - 5j
z3 = 7 + 0j
print(f"Konjugat von {z1} ist {z1.conjugate()}")
print(f"Konjugat von {z2} ist {z2.conjugate()}")
print(f"Konjugat von {z3} ist {z3.conjugate()}")
# Ausgabe:
# Konjugat von (3+4j) ist (3-4j)
# Konjugat von (-2-5j) ist (-2+5j)
# Konjugat von (7+0j) ist (7-0j)Das zweite Ergebnis zeigt die Regel an einem negativen Koeffizienten. Der Imaginärteil von z2 ist , sein Konjugat trägt deshalb , während der Realteil bei bleibt. Eine reelle Zahl wie z3 ist ihr eigenes Konjugat, weil ihr Imaginärteil bereits null ist.
Die Größe einer komplexen Zahl berechnen
Die Identität verbindet eine komplexe Zahl mit ihrem Betrag, und das Beispiel unten rechnet diese Identität im Code nach. Im normalen Python-Code rufst du für den Betrag einfach abs(z) auf, lies das Beispiel also als Begründung dafür, warum diese eingebaute Funktion funktioniert.
import math
# Betrag einer komplexen Zahl ueber das Konjugat berechnen
z = 3 + 4j
modulus_squared = z * z.conjugate()
modulus = math.sqrt(modulus_squared.real)
print(f"Komplexe Zahl: {z}")
print(f"Ihr Konjugat: {z.conjugate()}")
print(f"z × z*: {modulus_squared}")
print(f"Betrag |z|: {modulus}")
print(f"Eingebautes abs(z): {abs(z)}")
# Ausgabe:
# Komplexe Zahl: (3+4j)
# Ihr Konjugat: (3-4j)
# z × z*: (25+0j)
# Betrag |z|: 5.0
# Eingebautes abs(z): 5.0Die Multiplikation von mit seinem Konjugat löscht den Imaginärteil und lässt die reelle Zahl übrig. Die Wurzel aus dieser reellen Zahl ergibt , und das eingebaute abs(z) meldet in einem Aufruf denselben Wert.
Methoden für ganze Zahlen und Floats
Ganze Zahlen und Floats bringen Methoden mit, die zu ihrer eigenen Darstellung passen, und diese Methoden sind nicht gegen die Methoden komplexer Zahlen austauschbar. bit_length() zählt die Bits des absoluten Werts, to_bytes() schreibt diese Bits in eine Bytefolge, is_integer() prüft, ob ein Float einen Bruchteil hat, und as_integer_ratio() meldet den Bruch, den ein Float tatsächlich speichert.
| Methode | Zugehöriger Typ | Frage, die sie beantwortet |
|---|---|---|
bit_length() | int | Wie viele Bits braucht der absolute Wert |
to_bytes() | int | Welche Bytes stellen diesen Wert in gewählter Breite und Ordnung dar |
is_integer() | float | Hat dieser Float keinen Bruchteil |
as_integer_ratio() | float | Welchem genauen Bruch entspricht der gespeicherte Wert |
In modernem Python besitzt auch int die Methoden is_integer() und as_integer_ratio(): (42).is_integer() ergibt True, (42).as_integer_ratio() ergibt (42, 1). Die Tabelle nennt die in den Beispielen verwendeten Typen, nicht alle möglichen Besitzer einer Methode.
Methoden ganzer Zahlen
# Einige Methoden ganzer Zahlen
n = 42
# Methode bit_length() - berechnet die benoetigten Bits
print(f"Anzahl der Bits fuer {n}: {n.bit_length()}")
# Methode to_bytes() - wandelt in Bytes um
byte_representation = n.to_bytes(2, byteorder='big')
print(f"Byte-Darstellung von {n}: {byte_representation}")
# Ausgabe:
# Anzahl der Bits fuer 42: 6
# Byte-Darstellung von 42: b'\x00*'bit_length() zählt die Bits, die der absolute Wert der ganzen Zahl braucht, und lässt dabei das Vorzeichen sowie alle führenden Nullen weg. Hier erhält to_bytes() ausdrücklich eine Ausgabelänge und eine Byteordnung, deshalb beginnt das Ergebnis mit zwei Bytes mit einem Nullbyte, das die angeforderte Breite auffüllt.
Methoden von Floats
# Einige Methoden von Floats
f = 3.14159
# Methode is_integer() - prueft, ob der Float ganzzahlig ist
print(f"{f} ist ganzzahlig: {f.is_integer()}")
print(f"{4.0} ist ganzzahlig: {(4.0).is_integer()}")
# Methode as_integer_ratio() - liefert den Bruch
ratio = f.as_integer_ratio()
print(f"Verhaeltnis von {f}: {ratio}")
# Ausgabe:
# 3.14159 ist ganzzahlig: False
# 4.0 ist ganzzahlig: True
# Verhaeltnis von 3.14159: (3537115888337719, 1125899906842624)is_integer() prüft, ob ein endlicher Float keinen Bruchteil hat, deshalb fällt durch diese Prüfung, während sie besteht. as_integer_ratio() liefert den genauen Bruch aus der Binärdarstellung, und das erklärt, warum das Verhältnis für so große Zahlen trägt statt des erwarteten Dezimalbruchs.
Numerische Objekte prüfen und berechnen
Attribute und Methoden unterstützen auch Prüfungen und Umwandlungen, und diese beiden Schritte gehören zusammen. Du prüfst zuerst die Eingabe und rechnest danach, damit Werte außerhalb der gewählten Domainregeln vor der Rechnung abgelehnt werden können.
Die Eingabe vor dem Rechnen prüfen
Attribute können ausdrückliche Prüfregeln tragen. Die Funktion unten verlangt zuerst ein Objekt vom Typ complex, wendet dann zwei Beispielregeln auf seine Bestandteile an und meldet für jeden abgelehnten Fall einen Text.
def validate_complex_input(z):
"""Funktion zur Pruefung einer komplexen Eingabe"""
if not isinstance(z, complex):
return False, "Eingabe ist keine komplexe Zahl"
if z.real < 0:
return False, "Realteil darf nicht negativ sein"
if z.imag == 0:
return False, "Imaginaerteil darf nicht null sein"
return True, "Gueltige Eingabe"
# Prueffunktion testen
test_numbers = [3+4j, -2+5j, 7+0j, 2.5+1.5j]
for num in test_numbers:
is_valid, message = validate_complex_input(num)
print(f"{num}: {message}")Die Funktion liefert ein Paar aus zwei Werten, der Aufrufer erhält also Entscheidung und Begründung zusammen. Von den vier Testzahlen bestehen und alle drei Prüfungen, wird wegen des negativen Realteils abgelehnt, und wird abgelehnt, weil sein Imaginärteil null ist.
Mit komplexen Zahlen rechnen
def complex_operations(z1, z2):
"""Verschiedene Operationen auf komplexen Zahlen"""
print(f"Zahl 1: {z1}")
print(f"Zahl 2: {z2}")
print(f"Realteil von z1: {z1.real}")
print(f"Imaginaerteil von z1: {z1.imag}")
print(f"Konjugat von z1: {z1.conjugate()}")
# Mathematische Operationen
addition = z1 + z2
multiplication = z1 * z2.conjugate()
print(f"z1 + z2 = {addition}")
print(f"z1 × z2* = {multiplication}")
# Verwendungsbeispiel
z1 = 2 + 3j
z2 = 1 - 2j
complex_operations(z1, z2)Mit diesen Eingaben ergibt z1 + z2 den Wert , weil Realteile und Imaginärteile getrennt addiert werden. Der Ausdruck z1 * z2.conjugate() multipliziert mit und liefert .
Bestimme den numerischen Typ, und prüfe dann, ob eine Operation einen Bestandteil, eine Darstellung oder einen neuen Wert liefert, denn dieser Rückgabetyp entscheidet, wie der nächste Ausdruck das Ergebnis verwenden kann.