Python type() : tout sur la fonction

La fonction Python type() est une fonction Python intégrée pour travailler avec les types d’objets. Fonction de base de Python, elle appartient au noyau du langage.

À quoi sert la fonction Python type() ?

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

  1. Pour déterminer le type d’un objet Python ;
  2. Pour créer un nouveau type dynamique.

Nous allons d’abord considérer le premier cas, bien plus utilisé pour le développement au quotidien.

Déterminer le type d’un objet avec type()

Python est un langage typé dynamique. Cela signifie que les types ne sont déterminé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écessaire de déterminer 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 :


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 représentation 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, « Everything is an object ». En Python, le type d’un objet correspond à 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 maintenant la deuxième utilisation possible de la fonction Python type(). Appelée avec trois arguments, cette fonction nous permet de créer dynamiquement un nouveau type :

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

Sous cette forme, la fonction Python type() fonctionne comme le mot-clé class. Le code Type = type("Type", bases, dict) correspond à peu près à la définition de classe suivante :

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

Plus bas, vous trouverez quelques exemples concrets d’utilisation 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 instancier la métaclasse
Conseil

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

Comment fonctionne la fonction Python type() ?

Lors de l’utilisation de la fonction type() pour déterminer 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 indépendant :

# 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 maintenant quelques exemples de valeurs retournées par la fonction type() pour des objets de types diffé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() représentation 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 compréhension plus approfondie du système de POO de Python. L’objet intégré type de Python représente ce qu’on appelle une métaclasse. Une métaclasse se comporte avec une classe comme une classe se comporte avec un objet. En d’autres termes, une métaclasse est un modèle pour une classe, alors qu’une classe est un modèle pour un objet :

Modèle Instance
Classe Objet
Metaclasse 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éterminer le type d’un objet au moment de l’exécution. C’est toujours utile car Python est un langage typé dynamiquement. Dans un langage typé statiquement comme Java, un type est lié à une variable par déclaration 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éterminer 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éfinition d’une fonction, il est souvent nécessaire de vérifier que les arguments respectent certains critères. Par exemple, un argument ne peut se situer que dans une certaine fourchette, ou encore seuls les arguments de types définis sont autorisés. Pour éviter les erreurs d’exécution, par exemple.

Illustrons l’utilisation de la fonction type() à l’aide d’un exemple : nous allons définir une fonction qui additionne une liste de nombres. Pour que cela fonctionne, nous devons nous assurer que chaque argument est bien un nombre. Dans ce cas, type() sera utilisé dans une instruction 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’utilisation d’un langage interprété tel que Python est l’exécution interactive de code en boucle REPL (Read-Eval-Print-Loop). Cette approche aide à faire un prototypage rapide et un débogage en direct en inspectant les objets en mémoire.

Imaginons le scénario suivant : notre code inclut une variable answer qui doit contenir une valeur booléenne. Nous constatons que le type ne correspond 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 guillemets, erreur d’inattention 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 dynamiquement des classes Python avec la fonction type()

Nous l’avons vu, les classes Python peuvent être créées dynamiquement, 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. Commenç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écialisons la classe de base par héritage sur les balises spécifiques respectives 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 utiliserons 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 instancier une balise p et vérifier que l’affichage fonctionne correctement :

# 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éfinition 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 Comprehension 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 intéressant d’utiliser la fonction type() pour créer facilement plusieurs sous-classes apparentées. L’exemple plus complexe de la définition de classes pour la modélisation de cartes à jouer permet d’illustrer cette approche. Commençons par définir une superclasse 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

Maintenant, il est possible d’instancier les cartes individuelles facilement :

# 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 applications pour lesquelles la fonction atteint ses limites. Heureusement, Python dispose d’approches adaptées : nous allons en examiner quelques-unes.

Décomposer les hiérarchies d’héritage avec isinstance()

La fonction type() détermine uniquement le type réel d’un objet Python sans tenir compte de la hiérarchie 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éterminer :

# 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écomposer correctement le polymorphisme 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

Reconnaissance du type d’objet Python simplifiée avec match-case

Comme nous l’avons montré plus haut, la fonction type() en Python est souvent utilisée pour déterminer le type d’un objet au moment de l’exécution. Pour distinguer plusieurs types d’objet, on utilise dans ce cas une construction 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’instruction match-case. Celle-ci permet notamment de reconnaître des types sans appeler la fonction type().

Dans un bloc case, il est possible d’utiliser des fonctions de constructeur comme int(obj) ou str(obj). Le bloc est matché si l’objet a le type correspondant :

# 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 familiariser avec le langage ? Jetez un œil sur notre tutoriel Python ainsi que sur notre tour d’horizon des opérateurs Python.