2.33. Introspection

Une poignée de fonctions natives permettent à un programme en cours d’exécution de s’inspecter lui-même – les valeurs qu’il manipule, les espaces de noms dans lesquels ces valeurs résident, et les relations entre les classes. Recourez-y lorsque vous devez prendre des décisions en fonction de ce qu’un objet est réellement, plutôt que de ce que son appelant prétend qu’il est.

2.33.1. Identité et hachage

  • id() – un entier unique qui identifie un objet aussi longtemps qu’il est en vie. Deux noms qui lient le même objet renvoient le même id ; deux objets égaux mais distincts non.

>>> a = [1, 2, 3]
>>> b = a
>>> c = [1, 2, 3]
>>> id(a) == id(b)        # same list
True
>>> id(a) == id(c)        # equal but distinct
False

L’id n’est pas portable d’une exécution à l’autre et n’a de sens que pour distinguer « même objet ou objet différent ».

  • hash() – la valeur de hachage d’un objet, le même nombre que dict et set utilisent pour le retrouver. Deux objets égaux ont la même valeur de hachage ; seuls les types hachables (les valeurs immuables, pour l’essentiel) fonctionnent.

>>> hash("abc")           # some integer, build-dependent
-1600925533
>>> hash([1, 2])
TypeError: unhashable type: 'list'

2.33.2. Interroger les types et la capacité d’appel

  • type() – la classe exacte d’une valeur. type(x) is int demande « x est-il exactement un int » (sans les sous-classes) ; isinstance() est généralement ce que vous voulez à la place.

  • isinstance() – « x est-il une instance de cette classe, ou d’une sous-classe de celle-ci ? » L’outil standard pour la répartition fondée sur le type au sein des fonctions.

  • issubclass() – l’équivalent au niveau des classes. Il prend deux classes plutôt qu’une instance.

  • callable()True si l’argument peut être appelé avec (). Utile lorsque vous recevez un argument qui peut être une fonction ou une simple valeur.

>>> isinstance(3, int)
True
>>> isinstance(True, int)        # bool is a subclass of int
True
>>> issubclass(bool, int)
True
>>> callable(len)
True
>>> callable(10)
False

Un modèle qui utilise callable :

def call_or_return(x):
    return x() if callable(x) else x

2.33.3. Examiner les portées

  • globals() – l’espace de noms global du module sous forme de dict. Y lire fonctionne ; y écrire est bien réel, mais le faire en dehors de l’exploration au REPL rend un programme difficile à suivre.

  • locals() – l’espace de noms local au site d’appel. Au sein d’une fonction, il reflète les variables locales ; modifier le dict renvoyé n’est pas garanti de répercuter les changements dans les variables locales réelles (comportement défini par l’implémentation).

name = "OpenMV"

def f():
    x = 10
    print(globals()["name"])    # OpenMV
    print(locals())             # {'x': 10}

Ces deux fonctions sont utiles pour le débogage et pour les outils qui ont besoin de découvrir ce qui est défini. Recourez-y avec parcimonie dans du code ordinaire – une fonction qui modifie globals() est l’une des choses les plus difficiles à raisonner en Python.

2.33.4. Voir aussi

dir() et help(), abordées dans debugging, sont les outils d’introspection du quotidien pour explorer la surface d’un objet inconnu.