De la mauvaise utilisation de 'is' et '==' ...

Le
Salvatore
Bonjour la communauté,

Voici un petit bout de code qui m'intrigue,


>>> v = 'TEST'
>>> if not v is 'TEST':
print "v est different de 'TEST'"
else:
print "v est egal a 'TEST'"

v est egal a 'TEST'
>>>
>>>


>>> v = 'N/A'
>>> if not v is 'N/A':
print "v est different de 'N/A'"
else:
print "v est egal a 'N/A'"

v est different de 'N/A'
>>>
>>> v != 'N/A'
False


J'avoue que je ne comprend pas très bien le fonctionnement de
l'opérateur 'is' dans ces tests.
Manifestement le caractère '/' modifie son comportement
Curieusement, je n'avais encore jamais été confronté à cette situation.
Si quelqu'un a une explication, je suis preneur

Cordialement

Salvatore
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Bruno Desthuilliers
Le #650179
Bonjour la communauté,

Voici un petit bout de code qui m'intrigue,


v = 'TEST'
if not v is 'TEST':





if v is not 'TEST'

aurais été plus lisible AMHA.

Ceci étant dit, l'opérateur 'is' sert à tester l'identité de deux
objets, et non leur égalité. C'est en fait le strict équivalent de :

if id(v) != id('TEST')

Et ce n'est en aucun cas l'opérateur qui convient pour la comparaison
que tu fais ici. Si tu veux tester une égalité de valeur, utilise
l'opérateur '=='.

Pour info, voici deux ou trois cas d'utilisation correcte de 'is':

a = 'TEST'
b = a
print a is b

c = None
print c is None:

def toto():
pass

d = toto
print d is toto

etc... Comme tu peux le constater, dans aucun de ces cas on ne teste
contre un litéral.

(snip)

J'avoue que je ne comprend pas très bien le fonctionnement de
l'opérateur 'is' dans ces tests.
Manifestement le caractère '/' modifie son comportement


Manifestement, ta conclusion est (au moins partiellement) erronée. La
présence du slash ne modifie en rien le comportement de 'is', bien
qu'elle puisse modifier le résultat de ton test.

Curieusement, je n'avais encore jamais été confronté à cette situation.
Si quelqu'un a une explication, je suis preneur


Détail d'implémentation de CPython, qui tente autant que possible de
cacher certains objets immutables. Tu aurais pu avoir une surprise
similaire avec des entiers:

a = 1
print a is 1
True



b = 1024*1024
print b is 1024*1024
False








ou des expressions booléennes:
print a == 1
True



print (a == 1) is True
True



print a == 1 is True
False








Bref, et pour résumer : utilise '==' pour une égalité de valeur, et 'is'
pour des identités d'objets.

HTH




Bruno Desthuilliers
Le #650178
(snip)
is, c'est l'operateur d'égalité d'objet en mémoire.


(repost suite à erreur - Christophe, tu a probablement recu la réponse
en privé, si oui mes excuses pour la fausse manip)

'is' est l'opérateur de comparaison d'identité. C'est à dire que :

a is b

est strictement équivalent à:

id(a) == id(b)

(se référer à la définition de id())

Le fait que CPython utilise l'adresse mémoire comme identifiant unique
d'un objet, bien qu'évident d'un point de vue pratique, n'est qu'un
détail d'implémentation.

Et avant que quelqu'un ne le dise, oui, je sais, je suis puriste et
pédant !-)

MC
Le #649914
Bonsoir !

Je n'obtiens pas les mêmes résultats que toi.






--
@-salutations

Michel Claveau
William Dode
Le #649913
On 05-10-2007, MC wrote:
Bonsoir !

Je n'obtiens pas les mêmes résultats que toi.


moi si

In [1]: v='N/A'

In [2]: v is 'N/A'
Out[2]: False

In [3]: v='TEST'

In [4]: v is 'TEST'
Out[4]: True

curieusement le '/' seul ne pose pas de problème
In [10]: v='/'

In [11]: v is '/'
Out[11]: True

j'ai pas d'explication...

--
William Dodé - http://flibuste.net
Informaticien indépendant

Christophe Cavalaria
Le #649912
Salvatore wrote:

Bonjour la communauté,

Voici un petit bout de code qui m'intrigue,


v = 'TEST'
if not v is 'TEST':
... print "v est different de 'TEST'"



... else:
... print "v est egal a 'TEST'"
...
v est egal a 'TEST'







v = 'N/A'
if not v is 'N/A':
... print "v est different de 'N/A'"



... else:
... print "v est egal a 'N/A'"
...
v est different de 'N/A'

v != 'N/A'
False





J'avoue que je ne comprend pas très bien le fonctionnement de
l'opérateur 'is' dans ces tests.
Manifestement le caractère '/' modifie son comportement
Curieusement, je n'avais encore jamais été confronté à cette situation.
Si quelqu'un a une explication, je suis preneur

Cordialement

Salvatore


is, c'est l'operateur d'égalité d'objet en mémoire. Il est tout à fait
envisageable d'avoir en deux string différentes en mémoire ayant le même
contenu. A ce moment, les strings comparent à faux avec is mais à vrai avec
== car ce dernier test le contenu des objets

a is b <=> id(a) == id(b)

Après, la ligne de commande python ou le compilateur .py=>.pyc peut faire
certaines optimisations qui fait que ce genre de code renvoit vrai sur le
premier print :

a = "test"
b = "test"
print a is b
a += "e"
b += "e"
print a is b




Mais en général, vous obtenez toujours faux sur le deuxième même si
manifestement a == b.




Salvatore
Le #649911
Salvatore wrote:

Mais en général, vous obtenez toujours faux sur le deuxième même si
manifestement a == b.


Merci pour cette explication, Christophe.
Il faut en conclure que pour tester le 'contenu' d'une variable
il faut sytématiquement utiliser l'opérateur '==' et non l'opérateur
'is', qui lui est réservé pour tester l'identité de 2 objets.

Salvatore
Le #649910

curieusement le '/' seul ne pose pas de problème
In [10]: v='/'

In [11]: v is '/'
Out[11]: True


a = '/'
a is '/'
False




Décidément notre ami Python nous joue des tours :-)



Salvatore
Le #649909
Bref, et pour résumer : utilise '==' pour une égalité de valeur, et 'is'
pour des identités d'objets.

HTH


Entièrement d'accord Bruno :-)
Merci

jean-michel bain-cornu
Le #649908
Et avant que quelqu'un ne le dise, oui, je sais, je suis puriste et
pédant !-)


Aucune importance ! ...sans préjuger du fait éventuel que ce soit vrai ;-)

Encolpe Degoute
Le #666494
Bonjour la communauté,

Voici un petit bout de code qui m'intrigue,


v = 'TEST'
if not v is 'TEST':
.... print "v est different de 'TEST'"



.... else:
.... print "v est egal a 'TEST'"
....
v est egal a 'TEST'







v = 'N/A'
if not v is 'N/A':
.... print "v est different de 'N/A'"



.... else:
.... print "v est egal a 'N/A'"
....
v est different de 'N/A'

v != 'N/A'
False





J'avoue que je ne comprend pas très bien le fonctionnement de
l'opérateur 'is' dans ces tests.
Manifestement le caractère '/' modifie son comportement
Curieusement, je n'avais encore jamais été confronté à cette situation.
Si quelqu'un a une explication, je suis preneur


Pour faire un équivalence au C, 'is' vérifie une référence.
Mais python est avare en mémoire: s'il peu utiliser le même objet deux
fois il le fait:

_MARKER = 'XXX'

a = 'XXX'
a is _MARKER
True



a = a[:] # force la copie
a is _MARKER
True



a = a + 'X'
a is _MARKER
False




b = _MARKER
b is _MARKER
True



b = b + 'X'
b is _MARKER
False





Lorsque deux chaines de caractères sont identiques python utilise la
même référence en mémoire s'il considère que cela est pertinent, mais
pas toujours. Dans le cas des tests a et b il a fallu modifier la valeur
des variables pour changer de références.
Conclusion: utiliser 'is' sur des chaines de caractère est une source de
bug. Il vaut mieux utiliser '==' qui est plus adapté.

Maintenant, le cas des listes (mais pas des tuples):

_MARKER2 = ['1', '2']
c = _MARKER2

c is _MARKER2
True




c.append(3)
c is _MARKER2
True




c == _MARKER2
True




_MARKER2
['1', '2', 3]




La variable c, via l'affection initiale, partage la même référence que
le marqueur. Modifier la variable revient à modifier le marqueur.

Aller, la victoire sur les néo-zélandais mérite un petit mal de crane:

from copy import copy
d = copy(_MARKER2)

d is _MARKER2
False




d == _MARKER2
True




Que se passe-t-il ?
'is' vérifie les pointeurs et l'utilisation de 'copy' nous assure qu'ils
sont différents.
'==' vérifie les valeurs et l'utilisation de 'copy', ou de deepcopy dans
les cas les plus complexes, nous assure qu'elles sont identiques.

d.append(4)

d is _MARKER2
False




d == _MARKER2
False




La variable d est bien indépendante du marqueur.

Conclusion générale:
La question de l'utilisation de 'is' est un grand classique de python et
pour faire simple il ne faut pas l'utiliser sauf lorsque l'on veut
s'assurer que deux objets utilisent la même référence.
Le cas le plus fréquent de l'utilisation de 'is' est la vérification
d'une valeur passée en argument d'un fonction ou d'un méthode.


Amicalement,
--
Encolpe DEGOUTE
http://encolpe.degoute.free.fr/
Logiciels libres, hockey sur glace et autres activités cérébrales




Publicité
Poster une réponse
Anonyme