56 votes

Pourquoi le mot clé "is" a un comportement différent lorsqu'il y a un point dans la chaîne ?

>>> x = "google"
>>> x is "google"
True
>>> x = "google.com"
>>> x is "google.com"
False
>>>

Quelqu'un peut-il me donner des indications sur la raison pour laquelle c'est comme ça ?

Editar pour être sûr de ce qui précède, je viens de tester sur python 2.5.4, 2.6.5, 2.7b2, python 3.1 sur Windows et python 2.7b1 sur linux.

Il semble qu'il y ait une cohérence entre tous, donc c'est à dessein. Est-ce que j'ai raté quelque chose ?

Je viens de découvrir que depuis certains de mes domaines personnels le filtrage script échoue avec cela.

90voto

Alex Martelli Points 330805

is vérifie l'identité des objets, et toute implémentation de Python, lorsqu'elle rencontre le littéral des types immuables, est parfaitement libre de soit créer un nouvel objet de ce type immuable, o rechercher les objets existants de ce type pour voir si certains d'entre eux peuvent être réutilisés (en ajoutant une nouvelle référence au même objet sous-jacent). Il s'agit d'un choix pragmatique d'optimisation et de pas soumis à des contraintes sémantiques, de sorte que votre code ne doit jamais dépendre du chemin que peut prendre une implémentation donnée (ou il pourrait se briser avec une version de Python corrigée ou optimisée !)

Prenons un exemple :

>>> import dis
>>> def f():
...   x = 'google.com'
...   return x is 'google.com'
... 
>>> dis.dis(f)
  2           0 LOAD_CONST               1 ('google.com')
              3 STORE_FAST               0 (x)

  3           6 LOAD_FAST                0 (x)
              9 LOAD_CONST               1 ('google.com')
             12 COMPARE_OP               8 (is)
             15 RETURN_VALUE    

dans cette mise en œuvre particulière, à l'intérieur d'une fonction votre observation ne s'applique pas et un seul objet est fait pour le littéral (tout littéral), et, en effet :

>>> f()
True

D'un point de vue pragmatique, c'est parce qu'à l'intérieur d'une fonction, faire un passage par la table locale des constantes (pour économiser de la mémoire en ne créant pas de multiples objets immuables constants là où un seul suffit) est plutôt bon marché et rapide, et peut offrir de bons rendements de performance puisque la fonction peut être appelée de façon répétée par la suite.

Mais, la même mise en œuvre, à l'invite interactive ( Editar : Je pensais initialement que cela se produirait également au niveau supérieur d'un module, mais un commentaire de @Thomas m'a remis dans le droit chemin, voir plus loin) :

>>> x = 'google.com'
>>> y = 'google.com'
>>> id(x), id(y)
(4213000, 4290864)

ne prend PAS la peine d'essayer d'économiser de la mémoire de cette manière -- la id sont différents, c'est-à-dire des objets distincts. Il y a potentiellement des coûts plus élevés et des rendements plus faibles et donc l'heuristique de l'optimiseur de cette implémentation lui dit de ne pas s'embêter à chercher et de continuer.

Editar : au niveau du module supérieur, selon l'observation de @Thomas, donné par exemple :

$ cat aaa.py
x = 'google.com'
y = 'google.com'
print id(x), id(y)

Nous voyons à nouveau l'optimisation de la mémoire basée sur la table des constantes dans cette implémentation :

>>> import aaa
4291104 4291104

(fin de l'édition selon l'observation de @Thomas).

Enfin, toujours sur la même mise en œuvre :

>>> x = 'google'
>>> y = 'google'
>>> id(x), id(y)
(2484672, 2484672)

l'heuristique est différente ici parce que la chaîne littérale "ressemble à un identifiant" -- donc elle pourrait être utilisée dans une opération nécessitant un internage... donc l'optimiseur l'internalise de toute façon (et une fois internée, sa recherche devient très rapide bien sûr). Et en effet, surprise surprise.. :

>>> z = intern(x)
>>> id(z)
2484672

... x a a été intern pour la toute première fois (comme vous le voyez, la valeur de retour de la commande intern es le même en tant qu'objet x y y car il a la même id() ). Bien sûr, vous ne devriez pas non plus vous fier à cela - l'optimiseur ne ont d'internaliser quoi que ce soit automatiquement, il s'agit juste d'une heuristique d'optimisation. intern ed string, intern explicitement, juste pour être sûr. Lorsque vous hacer internaliser les chaînes de caractères de manière explicite... :

>>> x = intern('google.com')
>>> y = intern('google.com')
>>> id(x), id(y)
(4213000, 4213000)

...alors vous hacer assurer exactement le même objet (c'est-à-dire le même id() ) à chaque fois, ce qui vous permet d'appliquer des micro-optimisations telles que la vérification de l'utilisation de la fonction is plutôt que == (Je n'ai jamais trouvé que le gain de performance minuscule en valait la peine;-).

Editar Pour clarifier, voici le genre de différences de performances dont je parle, sur un Macbook Air lent... :

$ python -mtimeit -s"a='google';b='google'" 'a==b'
10000000 loops, best of 3: 0.132 usec per loop
$ python -mtimeit -s"a='google';b='google'" 'a is b'
10000000 loops, best of 3: 0.107 usec per loop
$ python -mtimeit -s"a='goo.gle';b='goo.gle'" 'a==b'
10000000 loops, best of 3: 0.132 usec per loop
$ python -mtimeit -s"a='google';b='google'" 'a is b'
10000000 loops, best of 3: 0.106 usec per loop
$ python -mtimeit -s"a=intern('goo.gle');b=intern('goo.gle')" 'a is b'
10000000 loops, best of 3: 0.0966 usec per loop
$ python -mtimeit -s"a=intern('goo.gle');b=intern('goo.gle')" 'a == b'
10000000 loops, best of 3: 0.126 usec per loop

...quelques dizaines de nanosecondes dans les deux sens, tout au plus. Donc, valant même réflexion seulement dans les situations les plus extrêmes "optimiser le [expletive deleted] de ce [expletive deleted] goulot d'étranglement de performance"!-)

15voto

Jeremy Brown Points 4950

"is" est un test d'identité. Python a un certain comportement de mise en cache pour les petits entiers et (apparemment) les chaînes de caractères. "is" est mieux utilisé pour les tests de singleton (ex. None ).

>>> x = "google"
>>> x is "google"
True
>>> id(x)
32553984L
>>> id("google")
32553984L
>>> x = "google.com"
>>> x is "google.com"
False
>>> id(x)
32649320L
>>> id("google.com")
37787888L

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X