Python tuple

Résolu/Fermé
Boto - Modifié le 9 juin 2023 à 15:14
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 12 juin 2023 à 14:21

Bonjour,

J'ai ce programme en python.

tup1 = 10, 11, 12
print(type(tup1)) 
tup2 = tup1
tup3 = tuple(tup1) 
print(tup1 == tup2) 
print(id(tup1) == id(tup2)) 
print(tup1 is tup2) 
print('-' * 15)
print(tup1 == tup3) 
print(id(tup1) == id(tup3))
print(tup1 is tup3)

Je ne comprends pas pourquoi les deux dernières lignes renvoient True. Pour moi, vu que l'on a utilisé le constructeur de tuple, tup3 a les mêmes valeurs que tup1 mais n'a pas la même référence. Est-ce que quelqu'un pourrait m'expliquer pourquoi cela renvoie True ?

2 réponses

J'ai ajouté les lignes suivantes à ton code:

print(id(tup1[0]) == id(tup3[0]))
tup4 = tuple(tup1[:])
print(id(tup4) == id(tup1))
tup5 = (10, 11, 12)
print(tup5 is tup1)

Un tuple n'étant pas mutable, il prend sans doute l'identité de ses composantes.

Petit test en invite:

>>> l = [1, 2, 3]
>>> m = l
>>> id(l) == id(m)
True
>>> m = l[:]
>>> id(m) == id(l)
False

Les listes sont mutables.

1

D'accord ça vient de là, merci beaucoup pour votre réponse.

0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
Modifié le 9 juin 2023 à 15:35

Bonjour,

Apparemment c'est plus subtil, et le résultat dépend de si on est dans l'interpréteur python (REPL) ou si on exécute un script python. Prenons cet extrait de code :

tup1 = (10, 11, 12)
tup2 = tup1
tup3 = tuple(tup1)
tup4 = (10, 11, 12)
print(tup1, id(tup1))
print(tup2, id(tup2))
print(tup3, id(tup3))
print(tup4, id(tup4))

Si je mets ce code dans un script que j'exécute, j'obtiens :

(mando@silk) (~) $ python3 toto.py
(10, 11, 12) 140590417604288
(10, 11, 12) 140590417604288
(10, 11, 12) 140590417604288
(10, 11, 12) 140590417604288

Si par contre je suis dans le REPL :

(mando@silk) (~) $ python3
Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> tup1 = (10, 11, 12)
>>> tup2 = tup1
>>> tup3 = tuple(tup1)
>>> tup4 = (10, 11, 12)
>>> print(tup1, id(tup1))
(10, 11, 12) 139713892358464
>>> print(tup2, id(tup2))
(10, 11, 12) 139713892358464
>>> print(tup3, id(tup3))
(10, 11, 12) 139713892358464
>>> print(tup4, id(tup4))
(10, 11, 12) 139713889771392

On voit qu’étonnement, tup4 n'a pas le même identifiant. Pourquoi ? Mystère. Mais du coup ça veut dire que "is" fera la distinction entre tup4 et les autres. On peut du coup se demander pourquoi tup3 n'est pas dans le même cas...

Si tuple était un "vrai" immutable (comme les chaînes de caractères ou les booléens) on devrait avoir toujours le même identifiant si les valeurs des deux variables comparées coïncident, et on pourrait utiliser l'opérateur is (qui compare les identifiants) sans problème :

>>> s1 = "abc"
>>> s2 = "abc"
>>> id(s1)
9942560
>>> id(s2)
9942560

J'observe le même comportement étrange sur les tuples avec ipython3 (ce qui pour le coup ne m'étonne pas si on part du principe qu'ipython3 n'est qu'une surcouche à python3).

Bref, pour comparer deux tuples, j'aurais tendance à utiliser systématiquement l'opérateur ==, car le comportement de l'opérateur is semble dépendre du contexte...

Bonne chance

1

Salut.

Pour ma part le comportement de is est tellement peu logique (presque un comportement indéterminé) que je fais comme tout le monde, je ne l'utilise que pour l'idendité de None...

>>> True is bool
False
>>> True is bool()
False
>>> False is bool
False
>>> False is bool()
True

0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812 > filou
12 juin 2023 à 14:21

Le comportement de is est bien défini : il compare juste l'identifiant des deux objets mis en jeu dans le test.

  • Pour les types immutables (bool, str, ...), is peut donc remplacer un test d'égalité. Les nouveaux linter python incitent d'ailleurs à comparer un booléan avec True ou False via is.
  • Pour les autres types, il ne faut utiliser is que si l'on souhaite vérifier qu'une instance d'un objet est bien une instance particulière. L'exemple ci-dessous illustre la nuance entre is et == :
    In [1]: l1 = [1, 2, 3]
    
    In [2]: l2 = [1, 2, 3]
    
    In [3]: l3 = l1
    
    In [4]: l1 == l2
    Out[4]: True
    
    In [5]: l2 == l3
    Out[5]: True
    
    In [6]: l1 == l3
    Out[6]: True
    
    In [7]: l1 is l2
    Out[7]: False
    
    In [8]: l1 is l3
    Out[8]: True
    
    In [9]: l3 is l1
    Out[9]: True

Bonne chance

0