# Python type()-Funktion

Die Python type()-Funktion ist eine **grundlegende Python-Funktion für die Arbeit mit Typen**. Als Teil der Python-Implementation gehört sie zum Kernbereich der Sprache.

## Wozu dient die type()-Funktion in Python?

Die type()-Funktion kommt in Python für **zwei ganz verschiedene Anwendungsfälle** zum Einsatz:

1. Typ eines Python-Objekts ermitteln
2. Dynamisch einen neuen Typ erzeugen

Wir betrachten zunächst **den ersten Fall**. Dieser ist im alltäglichen Gebrauch weitaus nützlicher.

### Mit type() den Typ eines Objekts ermitteln

Python ist eine dynamisch typisierte Sprache. Das bedeutet, dass Typen erst zur Laufzeit ermittelt werden und an Werte statt an Variablen gebunden sind. Aus diesem Umstand ergibt sich die Notwendigkeit, den **Typ eines Objekts zur Laufzeit zu ermitteln**.

Wir rufen Pythons type()-Funktion auf und übergeben ein Objekt als einzigen Parameter. Als Rückgabe erhalten wir den Typ des Objekts, z. B. `int` oder `str`:

```Python
# Type of `42` is `int`
assert type(42) == int
# Type of `str(42)` is `str`
assert type(str(42)) == str
```

Rufen wir im Python-REPL die type()-Funktion auf, **enthält die textuelle Repräsentation „class“ anstatt „type“**:

```Python
# Returns "<class 'int'>" inside REPL
type(42)
```

Was zunächst verwirrend scheint, ist durchaus sinnvoll, denn in Python gilt: „Everything is an object“. **In Python entspricht der Typ eines Objekts seiner Klasse**. So ist der Aufruf der type()-Funktion generell äquivalent zum Auslesen des `__class__`-Attributs:

```Python
# Should hold in most cases
assert type(obj) is obj.__class__
```

### Mit type() einen neuen Typ erzeugen

Betrachten wir nun die zweite Einsatzmöglichkeit der type()-Funktion. **Mit drei Argumenten aufgerufen**, erlaubt uns die Funktion, dynamisch einen neuen Typ zu erzeugen:

```Python
type(name, bases, dict, **kwds)
```

In dieser Form **fungiert die Python type()-Funktion analog zum `class`-Schlüsselwort**. Der Code `Type = type("Type", bases, dict)` entspricht in etwa der folgenden Klassen-Definition:

```Python
class <Type>(<bases>):
    <dict>
```

Weiter unten zeigen wir ein paar konkrete Beispiele für den Einsatz der **Python-type()-Funktion zum Erzeugen neuer Typen**. Vorab eine Übersicht der Argumente:

<table>
  <thead>
    <tr>
      <th>`name`</th>
      <th>`bases`</th>
      <th>`dict`</th>
      <th>`**kwds`</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Name des neuen Typs als String</td>
      <td>Tupel mit Basisklassen</td>
      <td>Dict mit Attributen der neuen Klasse</td>
      <td>Weitere Argumente für Metaklasse-Instanziierung</td>
    </tr>
  </tbody>
</table>

Tipp Mit [Deploy Now](https://www.ionos.de/hosting/deploy-now "Deploy Now - Websites und Apps via GitHub deployen - IONOS") von IONOS deployen Sie Websites und Apps einfach via GitHub.

## Wie funktioniert die Python-type()-Funktion?

Bei der Nutzung der type()-Funktion zum Ermitteln des Typs eines Objekts gilt: Der **Rückgabewert** ist nicht etwa ein String, sondern ein **eigenständiges Objekt**:

```Python
# Value returned by `type(42)` is not a string
assert type(42) != 'int'
# We get back an object named `int`
assert type(42) == int
```

Schauen wir uns ein paar **Beispiele von Rückgabewerten der type()-Funktion** für Objekte ganz verschiedener Typen an:

```Python
# Python objects of different types
different_objs = None, True, 42, 'John', ('Walter', 'White'), ...
# Print out the type of each object
for obj in different_objs:
    print(f"{obj}: {type(obj)}")
```

<table>
  <thead>
    <tr>
      <th>type()-Aufruf</th>
      <th>Textuelle Darstellung</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>`type(None)`</td>
      <td>`<class 'NoneType'>`</td>
    </tr>
    <tr>
      <td>`type(True)`</td>
      <td>`<class 'bool'>`</td>
    </tr>
    <tr>
      <td>`type(42)`</td>
      <td>`<class 'int'>`</td>
    </tr>
    <tr>
      <td>`type('John')`</td>
      <td>`<class 'str'>`</td>
    </tr>
    <tr>
      <td>`type(('Walter', 'White'))`</td>
      <td>`<class 'tuple'>`</td>
    </tr>
    <tr>
      <td>`type(...)`</td>
      <td>`<class 'ellipsis'>`</td>
    </tr>
  </tbody>
</table>

Es stellt sich die Frage: Was ist der **Typ des von type() zurückgegebenen Objekts**? Probieren wir es aus. Wir rufen die Python type()-Funktion auf und übergeben den Rückgabewert eines weiteren type()-Aufrufs:

```Python
# Returns: "<class 'type'>"
type(type(42))
```

Wir sehen: Neben Pythons eingebauter type()-Funktion existiert **der gleichnamige `type`-Typ**. Dies ist der Typ aller anderen Python-Typen, wie wir exemplarisch zeigen:

```Python
# DifferentPython objects
different_objs = None, True, 42, 'John', ('Walter', 'White'), ...
# Check the type of each object's type
for obj in different_objs:
    # Show that the type's type is always `type`
    assert type(type(obj)) is type
```

Der Typ eines jeden Python-Typs ist also `type`. Falls sich das verwirrend anhört – es wird noch besser: Selbst **der Typ des `type`-Objekts ist wiederum `type`**. Das lässt sich ewig fortsetzen, wie eine Schlange, die sich selbst in den Schwanz beißt:

```Python
# It's `type` all the way down
assert type(type(type(type))) is type
```

Um die Verwirrung aufzuklären, benötigt man ein tieferes Verständnis von Pythons OOP-System. **Pythons eingebautes `type`-Objekt repräsentiert eine sogenannte Metaklasse**. Eine Metaklasse verhält sich zu einer Klasse wie eine Klasse zu einem Objekt. Anders gesagt: Eine Metaklasse ist eine Vorlage (engl. *template*) für eine Klasse, während eine Klasse ein Template für ein Objekt ist:

<table>
  <thead>
    <tr>
      <th>Template</th>
      <th>Instanz</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Klasse</td>
      <td>Objekt</td>
    </tr>
    <tr>
      <td>Metaklasse</td>
      <td>Klasse</td>
    </tr>
    <tr>
      <td>Beispiel: `type`</td>
      <td>`int`, `str` etc.</td>
    </tr>
    <tr>
      <td>Beispiel:`int`</td>
      <td>42</td>
    </tr>
    <tr>
      <td>Beispiel: `str`</td>
      <td>“Walter White”</td>
    </tr>
  </tbody>
</table>

## Wie wird die type()-Funktion in Python eingesetzt?

Für gewöhnlich wird Pythons type()-Funktion eingesetzt, um **zur Laufzeit den Typ eines Objekts zu ermitteln**. Dies ist nützlich, da Python eine dynamisch typisierte Sprache ist. In einer statisch typisierten Sprache wie Java wird ein Typ per Deklaration an eine Variable gebunden und lässt sich zur Laufzeit nicht verändern:

```Java
// Declare variable as `boolean`
boolean answer;
// Attempting to assign `int` value
// Throws type error
answer = 42;
```

Demgegenüber sind Variablen in Python lediglich Namen, die auf typisierte Werte verweisen. Während der Ausführung des Codes lässt sich ein **Name jederzeit auf einen Wert mit einem anderen Typen verweisen**. Um den Typ einer Python-Variable zur Laufzeit festzustellen, benötigen wir also die type()-Funktion:

```Python
# Assign boolean value
answer = True
# Show that type is `bool`
assert type(answer) is bool
# Reassign integer value
answer = 42
# Show that type is now `int`
assert type(answer) is int
```

### Funktions-Argumente in Python auf ihren Typ überprüfen

Beim Definieren einer Funktion ist es oft notwendig, die **Argumente auf Einhaltung gewisser Kriterien zu überprüfen**. Beispielsweise darf ein Argument nur innerhalb bestimmter Grenzen liegen oder es sind nur Argumente geeigneter Typen erlaubt. So werden Laufzeitfehler vermieden.

Veranschaulichen wir uns den Einsatz der type()-Funktion an einem Beispiel: Wir definieren eine Funktion, die eine Liste von Zahlen aufaddiert. Damit das funktioniert, müssen wir **sicherstellen, dass jedes Argument tatsächlich eine Zahl ist**. Wir nutzen type() innerhalb einer `assert`-Anweisung:

```Python
# Function to add up numeric arguments
def add_numbers(*args):
    result = 0
    # Check each argument
    for arg in args:
        # Abort with error message if argument is not an `int` or `float`
        assert type(arg) in (int, float), f"Argument `{arg}` is not a number"
        # Add argument's value to total
        result += arg
    return result
# Show that it works for numbers
assert add_numbers(35, 7) == 42
# The following will fail
add_numbers(29, 'thirteen')
```

### Debugging im Python-REPL mit der type()-Funktion

Einer der Vorteile beim Einsatz einer interpretierten Sprache wie Python ist die **interaktive Ausführung von Code im REPL** (Read-Eval-Print-Loop). Der Ansatz erlaubt schnelle Prototypisierung und ein direktes Debugging via Inspektion der im Speicher befindlichen Objekte.

Stellen wir uns folgendes Szenario vor: Unser Code enthält eine Variable `answer`, die einen booleschen Wert enthalten soll. Wir stellen fest, dass der **Typ nicht unseren Erwartungen entspricht** und nutzen Pythons type()-Funktion, um den tatsächlichen Typ auszugeben. Wie sich herausstellt, haben wir versehentlich den booleschen Wert in Anführungszeichen geschrieben – ein besonders bei Anfängern und Anfängerinnen häufig auftretender Flüchtigkeitsfehler:

```Python
# Accidentally set to string
answer = 'False'
# Assertion will fail
assert type(answer) is bool
# Correct to boolean value
answer = False
# Now assertion holds
assert type(answer) is bool
```

### Python-Klassen mit der type()-Funktion dynamisch erzeugen

Wie wir gesehen haben, lassen sich Python-Klassen mit der type()-Funktion dynamisch – d. h. zur Laufzeit – erzeugen. **Nützlich ist dies u. a. für Familien von Klassen**, was wir am Beispiel von HTML-Tags veranschaulichen. Zunächst erzeugen wir eine Basisklasse `Tag`, deren Objekte sich selbst als HTML-Code darstellen können:

```Python
# Class representing HTML tag
class Tag:
    # Initialize HTML tag with contents
    def __init__(self, *args):
        # Join contents of tag
        self.content = "".join([arg.__str__() for arg in args])
    # String representation returns HTML
    def __str__(self):
        return f"<{self.name}>{self.content}</{self.name}>"
```

Im Anschluss **spezialisieren wir die Basisklasse per Vererbung auf die jeweiligen spezifischen Tags** wie `<p>` oder `<h1>`. Dazu rufen wir die type()-Funktion mit drei Argumenten auf:

```Python
# Create `P` class
P = type('P', (Tag,), {"name": 'p'})
```

1. Name der neuen Klasse als String.
2. Tupel mit Basisklassen.

Python erlaubt multiple Vererbung; um von nur einer Klasse abzuleiten, nutzen wir die Schreibweise `(ClassName,)`.
3. Dict mit dem Namen der Klasse und ggf. weiteren Einträgen.

Bei den Einträgen kann es sich auch um Funktionen handeln.

Im Anschluss **instanziieren wir ein `p`-Tag** und überprüfen, dass die Darstellung korrekt funktioniert:

```Python
# Instantiate `p` tag
greeting = P("Hello world")
assert str(greeting) == '&lt;p&gt;Hello world&lt;/p&gt;'
```

Derselbe Effekt lässt sich per **analoger Klassen-Definition** erzielen:

```Python
# Create `P` class
class P(Tag):
    name = 'p'
```

Als weiteres Beispiel erzeugen wir mit type() Klassen für Überschriften. Da die Erzeugung der Klassen dynamisch erfolgt, lassen sich **per List-Comprehension die Klassen für alle sechs Überschriften-Level** auf einen Schlag erzeugen:

```Python
h_1_to_6 = ( f"h{n}" for n in range(1, 7) )
headings = [type(heading, (Tag,), {"name": heading}) for heading in h_1_to_6]
```

Wie wir gezeigt haben, lohnt sich der Einsatz der type()-Funktion zum **komfortablen Erzeugen mehrerer verwandter Unterklassen**. Wir zeigen den Ansatz am komplexeren Beispiel, Klassen zur Modellierung von Spielkarten zu definieren. Zunächst definieren wir eine Überklasse `Card` per `class`-Schlüsselwort:

```Python
# Class representing abstract playing card
class Card:
    def __init__(self, number):
        self.number = number
    # String representation
    def __str__(self):
        return f"{self.number} of {self.suite}"
```

Im Anschluss **erzeugen wir Unterklassen für die vier Kartenfarben** mittels type():

```Python
# Create concrete types for each suite
Clubs = type('Clubs', (Card,), {'suite': 'Clubs'})
Diamonds = type('Diamonds', (Card,), {'suite': 'Diamonds'})
Hearts = type('Hearts', (Card,), {'suite': 'Hearts'})
Spades = type('Spades', (Card,), {'suite': 'Spades'})
```

Nun lassen sich die **einzelnen Karten problemlos instanziieren**:

```Python
# Instantiate a 7 of Spades
card = Spades(7)
# Show that it worked
assert str(card) == '7 of Spades'
```

## Wo stößt die type()-Funktion an ihre Grenzen?

Pythons type()-Funktion ist nützlich. Es gibt jedoch einige **Anwendungsfälle, bei deren Lösung die Funktion an ihre Grenzen stößt**. Glücklicherweise kennt Python passende Ansätze; schauen wir uns einige davon an.

### Vererbungs-Hierarchien mit isinstance() aufschlüsseln

type() ermittelt nur den tatsächlichen Typ eines Python-Objekts, lässt dabei jedoch die Vererbungs-Hierarchie außer Acht. Das sich daraus ergebende Dilemma veranschaulichen wir anhand unseres Spielkarten-Beispiels aus dem letzten Abschnitt. **Der Typ einer Pik 7 sollte sowohl „Spielkarte“ als auch „Pik“ sein**. Mit type() lässt sich dies jedoch nicht ermitteln:

```Python
# Create a Seven of Spades
card = Spades(7)
# Our card is a Spade alright
assert type(card) is Spades
# But not a card??
assert type(card) is not Card
```

Um den **zugrundeliegenden Polymorphismus korrekt aufzuschlüsseln**, bedienen wir uns der `isinstance()`-Funktion.

```Python
# Seven of Spades is a `Spade`
assert isinstance(card, Spades)
# And is also a `Card`
assert isinstance(card, Card)
```

### Mit match-case die Erkennung des Python-Objekt-Typs vereinfachen

Wie wir weiter oben gezeigt haben, wird die type()-Funktion häufig eingesetzt, um den Typ eines Objekts zur Laufzeit zu ermitteln. Um **mehrere mögliche Typen voneinander zu unterscheiden**, kommt ggf. ein `if-elif-else`-Konstrukt zum Einsatz:

```Python
# Determine type of object
if type(obj) is int:
    print("Int")
elif type(obj) is float:
    print("Float")
elif type(obj) is ...:
    print("...")
else:
    print("Something else")
```

Seit Version 3.10 kennt Python jedoch die `match-case`-Anweisung. Diese erlaubt u. a., **Typen ohne Aufruf der type()-Funktion zu erkennen**.

Innerhalb eines `case`-Blocks lassen sich Konstruktor-Funktionen wie `int(obj)` oder `str(obj)` einsetzen. Der Block matcht, wenn das Objekt den jeweiligen Typ hat:

```Python
# Example object
obj = 42
# Determine object type
match obj:
    case int(obj):
        print(f"{obj} is `int`")
    case float(obj):
        print(f"{obj} is `float`")
    case _:
        print(f"{obj} is something else")
```

Tipp Nutzen Sie für den Einstieg in die Sprache auch unser [Python-Tutorial](https://www.ionos.de/digitalguide/websites/web-entwicklung/python-tutorial/ "Python-Tutorial") sowie unsere Übersicht der [Python-Operatoren](https://www.ionos.de/digitalguide/websites/web-entwicklung/python-operatoren/ "Python-Operatoren").


This is a markdown version of: [https://www.ionos.de/digitalguide/websites/web-entwicklung/python-type-funktion/](https://www.ionos.de/digitalguide/websites/web-entwicklung/python-type-funktion/) for AI/LLM consumption.