La fonction Python type() est une fonction Python intégrée pour tra­vail­ler avec les types d’objets. Fonction de base de Python, elle ap­par­tient au noyau du langage.

À quoi sert la fonction Python type() ?

La fonction Python type() est utilisée dans deux cas très dif­fé­rents :

  1. Pour dé­ter­mi­ner le type d’un objet Python ;
  2. Pour créer un nouveau type dynamique.

Nous allons d’abord con­si­dé­rer le premier cas, bien plus utilisé pour le dé­ve­lop­pe­ment au quotidien.

Dé­ter­mi­ner le type d’un objet avec type()

Python est un langage typé dynamique. Cela signifie que les types ne sont dé­ter­mi­nés qu’au moment de l’exécution et qu’ils sont liés à des valeurs plutôt qu’à des variables. Résultat : il est né­ces­saire de dé­ter­mi­ner le type d’un objet au moment de l’exécution.

Nous appelons la fonction type() de Python et passons un objet comme seul paramètre. Nous recevons en retour le type de l’objet, par exemple int ou str :

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

Si nous appelons la fonction type() dans le REPL de Python, la re­pré­sen­ta­tion textuelle contient « class » au lieu de « type » :

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

Ce qui semble déroutant au premier abord est au bout du compte logique : en Python, « Eve­ry­thing is an object ». En Python, le type d’un objet cor­res­pond à sa classe. Ainsi, l’appel à la fonction type() équivaut en général à la lecture de l’attribut __class__ :

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

Créer un nouveau type avec type()

Voyons main­te­nant la deuxième uti­li­sa­tion possible de la fonction Python type(). Appelée avec trois arguments, cette fonction nous permet de créer dy­na­mi­que­ment un nouveau type :

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

Sous cette forme, la fonction Python type() fonc­tionne comme le mot-clé class. Le code Type = type("Type", bases, dict) cor­res­pond à peu près à la dé­fi­ni­tion de classe suivante :

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

Plus bas, vous trouverez quelques exemples concrets d’uti­li­sa­tion de la fonction Python type() pour créer de nouveaux types. Voici d’abord un aperçu des arguments :

name bases dict **kwds
Nom du nouveau type sous forme de chaîne Tuple avec classes de base Dict avec attributs de la nouvelle classe Autres arguments pour ins­tan­cier la mé­ta­classe
Conseil

Avec Deploy Now par IONOS, déployez vos sites Internet et vos applis avec GitHub !

Comment fonc­tionne la fonction Python type() ?

Lors de l’uti­li­sa­tion de la fonction type() pour dé­ter­mi­ner le type d’un objet, c’est la règle suivante qui s’applique : la valeur retour n’est pas une string mais un objet in­dé­pen­dant :

# 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

Voyons main­te­nant quelques exemples de valeurs re­tour­nées par la fonction type() pour des objets de types dif­fé­rents :

# 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
appel de type() re­pré­sen­ta­tion textuelle
type(None) <class ‘NoneType’>
type(True) <class ‘bool’>
type(42) <class ‘int’>
type(‘John’) <class ‘str’>
type((‘Walter’, ‘White’)) <class ‘tuple’>
type(...) <class ‘ellipsis’>

On peut se poser la question du type de l’objet retourné par type() ? Pour répondre à celle-ci, appelons la fonction Python type() et passons la valeur retournée par un autre appel type() :

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

On le voit bien ici : en plus de la fonction intégrée type() de Python, il existe le type type du même nom. Il s’agit du type de tous les autres types Python, comme on peut le voir dans cet exemple :

# 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

Le type de chaque type Python est donc type. Cela vous semble confus ? Il y a encore mieux : même le type de l’objet type est aussi type. Et cela peut continuer sans fin, tel un serpent qui se mord la queue :

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

Pour éviter la confusion, il faut se plonger dans la com­pré­hen­sion plus ap­pro­fon­die du système de POO de Python. L’objet intégré type de Python re­pré­sente ce qu’on appelle une mé­ta­classe. Une mé­ta­classe se comporte avec une classe comme une classe se comporte avec un objet. En d’autres termes, une mé­ta­classe est un modèle pour une classe, alors qu’une classe est un modèle pour un objet :

Modèle Instance
Classe Objet
Me­ta­classe Classe
Exemple : type int, str etc.
Exemple :int 42
Exemple : str “Walter White”

Comment utiliser la fonction type() en Python ?

En général, la fonction type() de Python est utilisée pour dé­ter­mi­ner le type d’un objet au moment de l’exécution. C’est toujours utile car Python est un langage typé dy­na­mi­que­ment. Dans un langage typé sta­ti­que­ment comme Java, un type est lié à une variable par dé­cla­ra­tion et ne peut pas être modifié lors de l’exécution :

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

En revanche, sous Python les variables ne sont que des noms qui font référence à des valeurs typées. Pendant l’exécution du code, un nom peut à tout moment faire référence à une valeur d’un autre type. Pour dé­ter­mi­ner le type d’une variable Python au moment de l’exécution, nous allons donc utiliser la fonction type() :

# 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

Vérifier le type des arguments de fonction en Python

À la dé­fi­ni­tion d’une fonction, il est souvent né­ces­saire de vérifier que les arguments res­pec­tent certains critères. Par exemple, un argument ne peut se situer que dans une certaine four­chette, ou encore seuls les arguments de types définis sont autorisés. Pour éviter les erreurs d’exécution, par exemple.

Il­lus­trons l’uti­li­sa­tion de la fonction type() à l’aide d’un exemple : nous allons définir une fonction qui ad­di­tionne une liste de nombres. Pour que cela fonc­tionne, nous devons nous assurer que chaque argument est bien un nombre. Dans ce cas, type() sera utilisé dans une ins­truc­tion assert :

# 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

Débogage dans le REPL Python avec la fonction type()

L’un des avantages à l’uti­li­sa­tion d’un langage in­ter­prété tel que Python est l’exécution in­te­rac­tive de code en boucle REPL (Read-Eval-Print-Loop). Cette approche aide à faire un pro­to­ty­page rapide et un débogage en direct en ins­pec­tant les objets en mémoire.

Imaginons le scénario suivant : notre code inclut une variable answer qui doit contenir une valeur booléenne. Nous cons­ta­tons que le type ne cor­res­pond pas à ce qui est attendu et utilisons la fonction type() de Python pour afficher le type réel. Il s’avère que nous avons écrit par erreur la valeur booléenne entre guil­le­mets, erreur d’inat­ten­tion fréquente notamment chez les débutants :

# 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

Créer dy­na­mi­que­ment des classes Python avec la fonction type()

Nous l’avons vu, les classes Python peuvent être créées dy­na­mi­que­ment, c’est-à-dire au moment de l’exécution, avec la fonction type(). Cela trouve toute son utilité pour les familles de classes et nous allons l’illustrer avec l’exemple des balises HTML. Com­men­çons par créer une classe de base Tag dont les objets peuvent s’afficher eux-mêmes sous forme de code HTML :

# 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

Ensuite, nous spé­cia­li­sons la classe de base par héritage sur les balises spé­ci­fiques res­pec­tives comme <p> ou <h1>. Pour ce faire, nous appelons la fonction type() avec trois arguments :

# Create `P` class
P = type(‘P’, (Tag,), {"name": ‘p’})
Python
  1. Nom de la nouvelle classe sous forme de string ;

  2. Tuples de classes de base ;

    Python permet l’héritage multiple ; pour dériver d’une seule classe, nous uti­li­se­rons la notation (ClassName,).

  3. Dict avec le nom de la classe et d’autres entrées au besoin.

    Les entrées peuvent aussi être des fonctions.

Ensuite, nous allons ins­tan­cier une balise p et vérifier que l’affichage fonc­tionne cor­rec­te­ment :

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

On peut obtenir le même effet par dé­fi­ni­tion de classe analogue :

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

Comme autre exemple, créons des classes pour les en-têtes avec type(). Comme la création des classes se fait de manière dynamique, il est possible de créer par List Com­pre­hen­sion les classes pour les six niveaux d’en-têtes d’un seul coup :

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

Comme nous l’avons montré, il est in­té­res­sant d’utiliser la fonction type() pour créer fa­ci­le­ment plusieurs sous-classes ap­pa­ren­tées. L’exemple plus complexe de la dé­fi­ni­tion de classes pour la mo­dé­li­sa­tion de cartes à jouer permet d’illustrer cette approche. Com­men­çons par définir une su­per­classe Card à l’aide d’un mot-clé class :

# 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

Ensuite, créons des sous-classes pour les quatre couleurs de cartes en utilisant 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

Main­te­nant, il est possible d’ins­tan­cier les cartes in­di­vi­duelles fa­ci­le­ment :

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

Quelles sont les limites de la fonction type() ?

Nous l’avons vu, la fonction Python type() est utile. Il existe cependant quelques ap­pli­ca­tions pour les­quelles la fonction atteint ses limites. Heu­reu­se­ment, Python dispose d’approches adaptées : nous allons en examiner quelques-unes.

Dé­com­po­ser les hié­rar­chies d’héritage avec isins­tance()

La fonction type() détermine uni­que­ment le type réel d’un objet Python sans tenir compte de la hié­rar­chie d’héritage. Le dilemme qui en résulte est illustré par l’exemple des cartes à jouer utilisé plus haut. Le type d’un 7 de pique devrait être à la fois « card » et « spades ». Or, la fonction type() ne permet pas de le dé­ter­mi­ner :

# 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

Pour dé­com­po­ser cor­rec­te­ment le po­ly­mor­phisme sous-jacent, nous allons utiliser la fonction isinstance().

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

Re­con­nais­sance du type d’objet Python sim­pli­fiée avec match-case

Comme nous l’avons montré plus haut, la fonction type() en Python est souvent utilisée pour dé­ter­mi­ner le type d’un objet au moment de l’exécution. Pour dis­tin­guer plusieurs types d’objet, on utilise dans ce cas une cons­truc­tion if-elif-else :

# 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

Depuis la version 3.10, Python reconnaît cependant l’ins­truc­tion match-case. Celle-ci permet notamment de re­con­naître des types sans appeler la fonction type().

Dans un bloc case, il est possible d’utiliser des fonctions de cons­truc­teur comme int(obj) ou str(obj). Le bloc est matché si l’objet a le type cor­res­pon­dant :

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

Vous souhaitez vous fa­mi­lia­ri­ser avec le langage ? Jetez un œil sur notre tutoriel Python ainsi que sur notre tour d’horizon des opé­ra­teurs Python.

Aller au menu principal