
En Python, les opérateurs in et not in testent l’appartenance à des listes, des tuples, des dictionnaires, etc.
Cet article décrit le contenu suivant.
- Comment utiliser l’opérateur in
- Utilisation de base
- Testé pour savoir s’ils sont égaux en valeur
- Avec l’instruction if
- dans le dictionnaire (dict)
- in pour la chaîne (str)
- pas dans (négation de dans)
- in pour plusieurs éléments
- Complexité temporelle de in
- Lent pour la liste :
O(n)
- Rapide pour l’ensemble :
O(1)
- Pour le dictionnaire
- Lent pour la liste :
- in in pour les déclarations et la liste des compréhensions
Le mot in est également utilisé dans pour les déclarations et les compréhensions de liste. Voir les articles suivants pour plus de détails.
Comment utiliser l’opérateur in
Utilisation de base
x dans y renvoie True si x est inclus dans y et False si ce n’est pas le cas.
print(1 in [0, 1, 2])
# True
print(100 in [0, 1, 2])
# False
Non seulement la liste, mais aussi le tuple, l’ensemble, la plage et d’autres objets itérables peuvent être utilisés.
print(1 in (0, 1, 2))
# True
print(1 in {0, 1, 2})
# True
print(1 in range(3))
# True
Le dictionnaire (dict) et la chaîne (str) sont décrits plus loin.
Testé pour savoir s’ils sont égaux en valeur
Test by in est basé sur le fait que les valeurs sont égales ou non ainsi que ==. Il vaut True si la valeur est égale même si le type est différent.
print(1.0 == 1)
# True
print(1.0 in [0, 1, 2])
# True
print(True == 1)
# True
print(True in [0, 1, 2])
# True
Notez que bool est une sous-classe de entier int, donc True et False sont respectivement équivalents à 1 et 0.
Avec l’instruction if
in renvoie une valeur booléenne (True, False) et peut être utilisée directement dans l’instruction if.
l = [0, 1, 2]
i = 0
if i in l:
print(f'{i} is a member of {l}.')
else:
print(f'{i} is not a member of {l}.')
# 0 is a member of [0, 1, 2].
l = [0, 1, 2]
i = 100
if i in l:
print(f'{i} is a member of {l}.')
else:
print(f'{i} is not a member of {l}.')
# 100 is not a member of [0, 1, 2].
Notez que les listes, les tuples, les chaînes, etc. sont évalués comme False s’ils sont vides et True s’ils ne le sont pas. Si vous souhaitez vérifier si un objet est vide ou non, vous pouvez utiliser l’objet tel quel.
l = [0, 1, 2]
if l:
print(f'{l} is not empty.')
else:
print(f'{l} is empty.')
# [0, 1, 2] is not empty.
l = []
if l:
print(f'{l} is not empty.')
else:
print(f'{l} is empty.')
# [] is empty.
Voir également les articles suivants pour les tests de valeur de vérité pour chaque type.
dans le dictionnaire (dict)
Le fonctionnement du dictionnaire (dict) teste la clé.
d = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
print('key1' in d)
# True
print('value1' in d)
# False
Utilisez values(), items() si vous voulez tester sur des valeurs ou des paires clé-valeur.
print('value1' in d.values())
# True
print(('key1', 'value1') in d.items())
# True
print(('key1', 'value2') in d.items())
# False
Voir l’article suivant pour plus de détails.
in pour la chaîne (str)
L’opération in pour la chaîne (str) teste l’existence d’une sous-chaîne.
print('a' in 'abc')
# True
print('x' in 'abc')
# False
print('ab' in 'abc')
# True
print('ac' in 'abc')
# False
pas dans (négation de dans)
x pas dans y renvoie la négation de x dans y.
print(10 in [1, 2, 3])
# False
print(10 not in [1, 2, 3])
# True
Le même résultat est renvoyé en ajoutant not à l’entier en opération.
print(not 10 in [1, 2, 3])
# True
Cependant, si vous ajoutez not à l’entier in operation, il sera interprété de deux manières, comme indiqué ci-dessous, il est donc recommandé d’utiliser le not in plus explicite.
print(not (10 in [1, 2, 3]))
# True
print((not 10) in [1, 2, 3])
# False
Étant donné que in a une priorité plus élevée que non, il est traité comme le premier s’il n’y a pas de parenthèses.
Ce dernier cas est reconnu comme suit.
print(not 10)
# False
print(False in [1, 2, 3])
# False
in pour plusieurs éléments
Si vous souhaitez vérifier si plusieurs éléments sont inclus, l’utilisation d’une liste de ces éléments comme suit ne fonctionnera pas. Il sera testé si la liste elle-même est incluse ou non.
print([0, 1] in [0, 1, 2])
# False
print([0, 1] in [[0, 1], [1, 0]])
# True
Utilisez et, ou ou ensembles.
Utilisez et, ou
Combinez plusieurs opérations en utilisant et et ou. Il sera testé si les deux ou l’un ou l’autre est inclus.
l = [0, 1, 2]
v1 = 0
v2 = 100
print(v1 in l and v2 in l)
# False
print(v1 in l or v2 in l)
# True
print((v1 in l) or (v2 in l))
# True
Étant donné que in et not in ont une priorité plus élevée que and et or, les parenthèses sont inutiles. Bien sûr, s’il est difficile à lire, vous pouvez le mettre entre parenthèses comme dans le dernier exemple.
Utiliser l’ensemble
Si vous avez beaucoup d’éléments à vérifier, il est plus facile d’utiliser l’ensemble que et, ou.
Par exemple, le fait que la liste A contienne tous les éléments de la liste B équivaut à savoir si la liste B est un sous-ensemble de la liste A.
l1 = [0, 1, 2, 3, 4]
l2 = [0, 1, 2]
l3 = [0, 1, 5]
l4 = [5, 6, 7]
print(set(l2) <= set(l1))
# True
print(set(l3) <= set(l1))
# False
Que la liste A ne contienne pas les éléments de la liste B équivaut à savoir si la liste A et la liste B sont relativement premières.
print(set(l1).isdisjoint(set(l4)))
# True
Si la liste A et la liste B ne sont pas relativement premières, cela signifie que la liste A contient au moins un élément de la liste B.
print(not set(l1).isdisjoint(set(l3)))
# True
Complexité temporelle de in
La vitesse d’exécution de l’opérateur in dépend du type de l’objet cible.
Les résultats de la mesure du temps d’exécution de in pour les listes, les ensembles et les dictionnaires sont présentés ci-dessous.
Notez que le code ci-dessous utilise la commande magique Jupyter Notebook %%timeit et ne fonctionne pas lorsqu’il est exécuté en tant que script Python.
Voir l’article suivant pour la complexité temporelle.
Prenons une liste de 10 éléments et 10000 éléments comme exemple.
n_small = 10
n_large = 10000
l_small = list(range(n_small))
l_large = list(range(n_large))
L’exemple de code ci-dessous est exécuté dans CPython 3.7.4, et bien sûr, les résultats peuvent varier en fonction de l’environnement.
Lent pour la liste : O(n)
La complexité temporelle moyenne de l’opérateur in pour les listes est O(n). Il devient plus lent lorsqu’il y a beaucoup d’éléments.
%%timeit
-1 in l_small
# 178 ns ± 4.78 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%%timeit
-1 in l_large
# 128 µs ± 11.5 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Le temps d’exécution varie fortement en fonction de la position de la valeur à rechercher. Il prend le plus de temps lorsque sa valeur est à la fin ou n’existe pas.
%%timeit
0 in l_large
# 33.4 ns ± 0.397 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%%timeit
5000 in l_large
# 66.1 µs ± 4.38 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%%timeit
9999 in l_large
# 127 µs ± 2.17 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Rapide pour l’ensemble : O(1)
La complexité temporelle moyenne de l’opérateur in pour les ensembles est O (1). Cela ne dépend pas du nombre d’éléments.
s_small = set(l_small)
s_large = set(l_large)
%%timeit
-1 in s_small
# 40.4 ns ± 0.572 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%%timeit
-1 in s_large
# 39.4 ns ± 1.1 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
Le temps d’exécution ne change pas en fonction de la valeur à rechercher.
%%timeit
0 in s_large
# 39.7 ns ± 1.27 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%%timeit
5000 in s_large
# 53.1 ns ± 0.974 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%%timeit
9999 in s_large
# 52.4 ns ± 0.403 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
Si vous souhaitez répéter l’opération pour une liste comportant de nombreux éléments, il est plus rapide de la convertir en ensemble à l’avance.
%%timeit
for i in range(n_large):
i in l_large
# 643 ms ± 29.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
s_large_ = set(l_large)
for i in range(n_large):
i in s_large_
# 746 µs ± 6.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Notez qu’il faut du temps pour convertir une liste en un ensemble, il peut donc être plus rapide de la conserver en tant que liste si le nombre d’opérations est petit.
Pour le dictionnaire
Prenons le dictionnaire suivant comme exemple.
d = dict(zip(l_large, l_large))
print(len(d))
# 10000
print(d[0])
# 0
print(d[9999])
# 9999
Comme mentionné ci-dessus, le fonctionnement du dictionnaire teste les clés.
La clé du dictionnaire est une valeur unique ainsi que l’ensemble, et le temps d’exécution est à peu près le même que pour les ensembles.
%%timeit
for i in range(n_large):
i in d
# 756 µs ± 24.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
D’autre part, les valeurs du dictionnaire peuvent être dupliquées comme une liste. Le temps d’exécution de in for values() est à peu près le même que pour les listes.
dv = d.values()
%%timeit
for i in range(n_large):
i in dv
# 990 ms ± 28.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Les paires clé-valeur sont uniques. Le temps d’exécution de in for items() est d’environ set + α.
di = d.items()
%%timeit
for i in range(n_large):
(i, i) in di
# 1.18 ms ± 26.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
in in pour les déclarations et la liste des compréhensions
Le mot in est également utilisé dans pour les déclarations et les compréhensions de liste.
l = [0, 1, 2]
for i in l:
print(i)
# 0
# 1
# 2
print([i * 10 for i in l])
# [0, 10, 20]
Voir les articles suivants pour plus de détails sur les déclarations et les compréhensions de liste.
Notez que l’opérateur in peut être utilisé comme condition dans les compréhensions de liste, ce qui prête à confusion.
l = ['oneXXXaaa', 'twoXXXbbb', 'three999aaa', '000111222']
l_in = [s for s in l if 'XXX' in s]
print(l_in)
# ['oneXXXaaa', 'twoXXXbbb']
Le premier in est in pour les compréhensions de liste, et le second in est l’opérateur in.