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 quedictetsetutilisent 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 intdemande « 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()–Truesi 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 dedict. 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.