# Attribute und Methoden von Zahlen

> For AI agents: use [llms.txt](https://nakafa.com/llms.txt) for the site index. Markdown versions are available by appending `.md` to content URLs or sending `Accept: text/markdown`.

URL: https://nakafa.com/de/faecher/ki-und-data-science/ki-programmierung/zahlen-attribute-und-methoden
Source: https://raw.githubusercontent.com/nakafaai/aksara/992eb09ded1422859aca3966c80b52a16b2832f4/packages/corpus/material/lesson/ai-ds/ai-programming/number-attribute-method/de.mdx

Numerische Python-Objekte werden anhand ihrer Typen, Attribute, Methoden und komplexen Rechenoperationen unterschieden.

---

## Zahlen als Objekte

Jede Zahl in Python ist ein Objekt mit einem [numerischen Typ](https://nakafa.com/de/faecher/ki-und-data-science/ki-programmierung/zahlen). Dieser Typ bestimmt, welche Attribute und Methoden du über die Punktschreibweise erreichen kannst.

Die Schreibweise $$5$$ erzeugt einen `int`, die Schreibweise $$3.14$$ einen `float`. Die hier behandelten eingebauten numerischen Objekte sind <Highlight>unveränderlich</Highlight>. Ein Methodenaufruf wie `conjugate()` gibt ein Ergebnis zurück, ohne den Wert des ursprünglichen Objekts zu ändern.

Visible text: Die Schreibweise erzeugt einen `int`, die Schreibweise einen `float`. Die hier behandelten eingebauten numerischen Objekte sind <Highlight>unveränderlich</Highlight>. 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](https://nakafa.com/de/faecher/ki-und-data-science/ki-programmierung/unveraenderlich-veraenderlich-identitaet): 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.

File: complex_example.py
```python
# 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 <Highlight>Klasse des Werts</Highlight>, 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.

File: type_example.py
```python
# 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 <Highlight>Floats zurück, auch bei ganzen Zahlen</Highlight>.

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.

File: real_attribute.py
```python
# 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.0
```

### Das Attribut imag

Das Attribut `imag` liefert den **Koeffizienten von** $$i$$, 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.

Visible text: 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.

File: imag_attribute.py
```python
# 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.0
```

Das Ergebnis für `z2` ist $$-4.0$$, 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 $$9.0$$ mit dem Realteil $$0.0$$.

Visible text: Das 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 $$z=a+bi$$ liefert `conjugate()` den Wert $$\overline{z}=a-bi$$. Der Realteil behält seinen Wert und <Highlight>nur der Imaginärteil wechselt das Vorzeichen</Highlight>, wodurch das Konjugat das Spiegelbild der Zahl an der reellen Achse wird.

Visible text: Für liefert `conjugate()` den Wert . Der Realteil behält seinen Wert und <Highlight>nur der Imaginärteil wechselt das Vorzeichen</Highlight>, wodurch das Konjugat das Spiegelbild der Zahl an der reellen Achse wird.

File: conjugate_method.py
```python
# 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 $$-5$$, sein Konjugat trägt deshalb $$+5$$, während der Realteil bei $$-2$$ bleibt. Eine reelle Zahl wie `z3` ist ihr eigenes Konjugat, weil ihr Imaginärteil bereits null ist.

Visible text: 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 $$z\overline{z}=|z|^2$$ **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.

Visible text: 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.

File: conjugate_practical.py
```python
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.0
```

Die Multiplikation von $$z$$ mit seinem Konjugat löscht den Imaginärteil und lässt die reelle Zahl $$25$$ übrig. Die Wurzel aus dieser reellen Zahl ergibt $$5.0$$, und das eingebaute `abs(z)` meldet in einem Aufruf denselben Wert.

Visible text: Die 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

File: integer_methods.py
```python
# 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

File: float_methods.py
```python
# 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 $$3.14159$$ durch diese Prüfung, während $$4.0$$ sie besteht. `as_integer_ratio()` liefert <Highlight>den genauen Bruch aus der Binärdarstellung</Highlight>, und das erklärt, warum das Verhältnis für $$3.14159$$ so große Zahlen trägt statt des erwarteten Dezimalbruchs.

Visible text: `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 <Highlight>den genauen Bruch aus der Binärdarstellung</Highlight>, 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.

File: data_validation.py
```python
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 $$3+4j$$ und $$2.5+1.5j$$ alle drei Prüfungen, $$-2+5j$$ wird wegen des negativen Realteils abgelehnt, und $$7+0j$$ wird abgelehnt, weil sein Imaginärteil null ist.

Visible text: 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

File: math_calculations.py
```python
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 $$3+1j$$, weil **Realteile und Imaginärteile getrennt addiert** werden. Der Ausdruck `z1 * z2.conjugate()` multipliziert $$2+3j$$ mit $$1+2j$$ und liefert $$-4+7j$$.

Visible text: 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.