Die Python type()-Funktion ist eine grund­le­gen­de Python-Funktion für die Arbeit mit Typen. Als Teil der Python-Im­ple­men­ta­ti­on gehört sie zum Kern­be­reich der Sprache.

Wozu dient die type()-Funktion in Python?

Die type()-Funktion kommt in Python für zwei ganz ver­schie­de­ne An­wen­dungs­fäl­le zum Einsatz:

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

Wir be­trach­ten zunächst den ersten Fall. Dieser ist im all­täg­li­chen Gebrauch weitaus nütz­li­cher.

Mit type() den Typ eines Objekts ermitteln

Python ist eine dynamisch ty­pi­sier­te Sprache. Das bedeutet, dass Typen erst zur Laufzeit ermittelt werden und an Werte statt an Variablen gebunden sind. Aus diesem Umstand ergibt sich die Not­wen­dig­keit, 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:

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

Rufen wir im Python-REPL die type()-Funktion auf, enthält die textuelle Re­prä­sen­ta­ti­on „class“ anstatt „type“:

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

Was zunächst ver­wir­rend scheint, ist durchaus sinnvoll, denn in Python gilt: „Ever­y­thing is an object“. In Python ent­spricht der Typ eines Objekts seiner Klasse. So ist der Aufruf der type()-Funktion generell äqui­va­lent zum Auslesen des __class__-Attributs:

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

Mit type() einen neuen Typ erzeugen

Be­trach­ten wir nun die zweite Ein­satz­mög­lich­keit der type()-Funktion. Mit drei Ar­gu­men­ten auf­ge­ru­fen, erlaubt uns die Funktion, dynamisch einen neuen Typ zu erzeugen:

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

In dieser Form fungiert die Python type()-Funktion analog zum class-Schlüs­sel­wort. Der Code Type = type("Type", bases, dict) ent­spricht in etwa der folgenden Klassen-De­fi­ni­ti­on:

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

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:

name bases dict **kwds
Name des neuen Typs als String Tupel mit Ba­sis­klas­sen Dict mit At­tri­bu­ten der neuen Klasse Weitere Argumente für Me­ta­klas­se-In­stan­zi­ie­rung
Tipp

Mit Deploy Now von IONOS deployen Sie Websites und Apps einfach via GitHub.

Wie funk­tio­niert die Python-type()-Funktion?

Bei der Nutzung der type()-Funktion zum Ermitteln des Typs eines Objekts gilt: Der Rück­ga­be­wert ist nicht etwa ein String, sondern ein ei­gen­stän­di­ges Objekt:

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

Schauen wir uns ein paar Beispiele von Rück­ga­be­wer­ten der type()-Funktion für Objekte ganz ver­schie­de­ner Typen an:

# 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)}")
Python
type()-Aufruf Textuelle Dar­stel­lung
type(None) <class 'NoneType'>
type(True) <class 'bool'>
type(42) <class 'int'>
type('John') <class 'str'>
type(('Walter', 'White')) <class 'tuple'>
type(...) <class 'ellipsis'>

Es stellt sich die Frage: Was ist der Typ des von type() zu­rück­ge­ge­be­nen Objekts? Probieren wir es aus. Wir rufen die Python type()-Funktion auf und übergeben den Rück­ga­be­wert eines weiteren type()-Aufrufs:

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

Wir sehen: Neben Pythons ein­ge­bau­ter type()-Funktion existiert der gleich­na­mi­ge type-Typ. Dies ist der Typ aller anderen Python-Typen, wie wir ex­em­pla­risch zeigen:

# 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
Python

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

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

Um die Ver­wir­rung auf­zu­klä­ren, benötigt man ein tieferes Ver­ständ­nis von Pythons OOP-System. Pythons ein­ge­bau­tes type-Objekt re­prä­sen­tiert eine so­ge­nann­te Me­ta­klas­se. Eine Me­ta­klas­se verhält sich zu einer Klasse wie eine Klasse zu einem Objekt. Anders gesagt: Eine Me­ta­klas­se ist eine Vorlage (engl. template) für eine Klasse, während eine Klasse ein Template für ein Objekt ist:

Template Instanz
Klasse Objekt
Me­ta­klas­se Klasse
Beispiel: type int, str etc.
Beispiel:int 42
Beispiel: str “Walter White”

Wie wird die type()-Funktion in Python ein­ge­setzt?

Für ge­wöhn­lich wird Pythons type()-Funktion ein­ge­setzt, um zur Laufzeit den Typ eines Objekts zu ermitteln. Dies ist nützlich, da Python eine dynamisch ty­pi­sier­te Sprache ist. In einer statisch ty­pi­sier­ten Sprache wie Java wird ein Typ per De­kla­ra­ti­on an eine Variable gebunden und lässt sich zur Laufzeit nicht verändern:

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

Dem­ge­gen­über sind Variablen in Python lediglich Namen, die auf ty­pi­sier­te Werte verweisen. Während der Aus­füh­rung des Codes lässt sich ein Name jederzeit auf einen Wert mit einem anderen Typen verweisen. Um den Typ einer Python-Variable zur Laufzeit fest­zu­stel­len, benötigen wir also die type()-Funktion:

# 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
Python

Funktions-Argumente in Python auf ihren Typ über­prü­fen

Beim De­fi­nie­ren einer Funktion ist es oft notwendig, die Argumente auf Ein­hal­tung gewisser Kriterien zu über­prü­fen. Bei­spiels­wei­se darf ein Argument nur innerhalb be­stimm­ter Grenzen liegen oder es sind nur Argumente ge­eig­ne­ter Typen erlaubt. So werden Lauf­zeit­feh­ler vermieden.

Ver­an­schau­li­chen wir uns den Einsatz der type()-Funktion an einem Beispiel: Wir de­fi­nie­ren eine Funktion, die eine Liste von Zahlen auf­ad­diert. Damit das funk­tio­niert, müssen wir si­cher­stel­len, dass jedes Argument tat­säch­lich eine Zahl ist. Wir nutzen type() innerhalb einer assert-Anweisung:

# 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')
Python

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

Einer der Vorteile beim Einsatz einer in­ter­pre­tier­ten Sprache wie Python ist die in­ter­ak­ti­ve Aus­füh­rung von Code im REPL (Read-Eval-Print-Loop). Der Ansatz erlaubt schnelle Pro­to­ty­pi­sie­rung und ein direktes Debugging via In­spek­ti­on der im Speicher be­find­li­chen Objekte.

Stellen wir uns folgendes Szenario vor: Unser Code enthält eine Variable answer, die einen boole­schen Wert enthalten soll. Wir stellen fest, dass der Typ nicht unseren Er­war­tun­gen ent­spricht und nutzen Pythons type()-Funktion, um den tat­säch­li­chen Typ aus­zu­ge­ben. Wie sich her­aus­stellt, haben wir ver­se­hent­lich den boole­schen Wert in An­füh­rungs­zei­chen ge­schrie­ben – ein besonders bei Anfängern und An­fän­ge­rin­nen häufig auf­tre­ten­der Flüch­tig­keits­feh­ler:

# 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

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 ver­an­schau­li­chen. Zunächst erzeugen wir eine Ba­sis­klas­se Tag, deren Objekte sich selbst als HTML-Code dar­stel­len können:

# 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}>"
Python

Im Anschluss spe­zia­li­sie­ren wir die Ba­sis­klas­se per Vererbung auf die je­wei­li­gen spe­zi­fi­schen Tags wie <p> oder <h1>. Dazu rufen wir die type()-Funktion mit drei Ar­gu­men­ten auf:

# Create `P` class
P = type('P', (Tag,), {"name": 'p'})
Python
  1. Name der neuen Klasse als String.

  2. Tupel mit Ba­sis­klas­sen.

    Python erlaubt multiple Vererbung; um von nur einer Klasse ab­zu­lei­ten, nutzen wir die Schreib­wei­se (ClassName,).

  3. Dict mit dem Namen der Klasse und ggf. weiteren Einträgen.

    Bei den Einträgen kann es sich auch um Funk­tio­nen handeln.

Im Anschluss in­stan­zi­ie­ren wir ein p-Tag und über­prü­fen, dass die Dar­stel­lung korrekt funk­tio­niert:

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

Derselbe Effekt lässt sich per analoger Klassen-De­fi­ni­ti­on erzielen:

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

Als weiteres Beispiel erzeugen wir mit type() Klassen für Über­schrif­ten. Da die Erzeugung der Klassen dynamisch erfolgt, lassen sich per List-Com­pre­hen­si­on die Klassen für alle sechs Über­schrif­ten-Level auf einen Schlag erzeugen:

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]
Python

Wie wir gezeigt haben, lohnt sich der Einsatz der type()-Funktion zum kom­for­ta­blen Erzeugen mehrerer ver­wand­ter Un­ter­klas­sen. Wir zeigen den Ansatz am kom­ple­xe­ren Beispiel, Klassen zur Mo­del­lie­rung von Spiel­kar­ten zu de­fi­nie­ren. Zunächst de­fi­nie­ren wir eine Über­klas­se Card per class-Schlüs­sel­wort:

# 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}"
Python

Im Anschluss erzeugen wir Un­ter­klas­sen für die vier Kar­ten­far­ben mittels type():

# 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'})
Python

Nun lassen sich die einzelnen Karten pro­blem­los in­stan­zi­ie­ren:

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

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

Pythons type()-Funktion ist nützlich. Es gibt jedoch einige An­wen­dungs­fäl­le, bei deren Lösung die Funktion an ihre Grenzen stößt. Glück­li­cher­wei­se kennt Python passende Ansätze; schauen wir uns einige davon an.

Ver­er­bungs-Hier­ar­chien mit is­in­s­tance() auf­schlüs­seln

type() ermittelt nur den tat­säch­li­chen Typ eines Python-Objekts, lässt dabei jedoch die Ver­er­bungs-Hier­ar­chie außer Acht. Das sich daraus ergebende Dilemma ver­an­schau­li­chen wir anhand unseres Spiel­kar­ten-Beispiels aus dem letzten Abschnitt. Der Typ einer Pik 7 sollte sowohl „Spiel­kar­te“ als auch „Pik“ sein. Mit type() lässt sich dies jedoch nicht ermitteln:

# 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
Python

Um den zu­grun­de­lie­gen­den Po­ly­mor­phis­mus korrekt auf­zu­schlüs­seln, bedienen wir uns der isinstance()-Funktion.

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

Mit match-case die Erkennung des Python-Objekt-Typs ver­ein­fa­chen

Wie wir weiter oben gezeigt haben, wird die type()-Funktion häufig ein­ge­setzt, um den Typ eines Objekts zur Laufzeit zu ermitteln. Um mehrere mögliche Typen von­ein­an­der zu un­ter­schei­den, kommt ggf. ein if-elif-else-Konstrukt zum Einsatz:

# 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")
Python

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 Kon­struk­tor-Funk­tio­nen wie int(obj) oder str(obj) einsetzen. Der Block matcht, wenn das Objekt den je­wei­li­gen Typ hat:

# 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")
Python
Tipp

Nutzen Sie für den Einstieg in die Sprache auch unser Python-Tutorial sowie unsere Übersicht der Python-Ope­ra­to­ren.

Zum Hauptmenü