Partage
  • Partager sur Facebook
  • Partager sur Twitter

Quand utiliser "is"/"is not"

Sujet résolu
    25 novembre 2011 à 14:32:30

    Bonjour a tous,

    J'ai beau chercher je trouve aucune bonne explication quand a l'utilisation de
    is
    is not
    

    Lorsque je tape
    help("is")

    Tout a la fin j'ai une explication me disant que c'est pour comparer les types mais je trouve régulièrement des posts ou l'on s'en sert autrement que pour ça.

    Donc je voulais savoir s'il y a une difference a utiliser is a la place de == et is not a la place de !=

    Merci d'avance
    • Partager sur Facebook
    • Partager sur Twitter
      25 novembre 2011 à 17:06:33

      Selon help("is") :

      Citation

      The operators is and is not test for object identity: x is y is true if and only if x and y are the same object. x is not y yields for the inverse truth value.



      On voit donc qu'il n'y a jamais de comparaison d'égalité entre les objets, mais uniquement entre leur identité. Qu'est-ce que leur identité ? Utilisons la fonction id :
      >>> foo = 1
      >>> bar = 1
      >>> print(id(foo), id(bar))
      506081728 506081728
      >>> foo is bar
      True
      >>> foo == bar
      True
      

      Dans ce cas, is et == retourne la même chose, parce que foo et bar contienne le même objet 1 en mémoire.

      Faisons un autre test :
      >>>> foo = [1,2,3]
      >>> bar = foo[:]
      >>> foo is bar
      False
      >>> foo == bar
      True
      >>> print(id(foo), id(bar))
      36232968 36300808
      

      Notons d'abord que foo[:] crée une copie de la liste.

      Dans cet exemple, foo est égal à bar. Les deux variables contiennent la même liste [1,2,3]. Par contre, en mémoire, ils ne référencent pas le même objet.
      C'est la raison pour laquelle l'opérateur is retourne faux même si les deux variables sont égales.

      Dernier exemple, pour bien comprendre les références :
      >>> foo = [1,2,3]
      >>> bar = foo
      >>> foo is bar
      True
      >>> print(foo, bar)
      [1,2,3] [1,2,3]
      >>> foo.append(4)
      >>> print(foo, bar)
      [1,2,3,4] [1,2,3,4]
      

      On voit bien dans ce cas que les deux objets référencent le même en mémoire, parce que quand on applique une méthode sur foo, bar est également modifié.
      • Partager sur Facebook
      • Partager sur Twitter
        25 novembre 2011 à 23:50:51

        Citation : Fayden


        >>> foo = 1
        >>> bar = 1
        >>> print(id(foo), id(bar))
        506081728 506081728
        >>> foo is bar
        True
        >>> foo == bar
        True
        


        Dans ce cas, is et == retourne la même chose, parce que foo et bar contienne le même objet 1 en mémoire.



        Pour des entiers plus grands, ça ne marche plus :


        >>> x=123456789
        >>> y=123456789
        >>> id(x)
        149427300
        >>> id(y)
        149427216
        >>>
        
        • Partager sur Facebook
        • Partager sur Twitter
          26 novembre 2011 à 5:21:50

          Ah merci je venais de comprendre avant de voir la réponse de candide qui me fait douter.

          car logiquement x et y pointe sur le même objet en memoire qui est 123456789 donc on devrait avoir True :-°
          • Partager sur Facebook
          • Partager sur Twitter
            26 novembre 2011 à 7:30:49

            C'est un exemple parmi tant d'autres, Python gère visiblement les entiers plus grands d'une façon différente, ça ne change rien au concept.
            • Partager sur Facebook
            • Partager sur Twitter
              26 novembre 2011 à 12:40:32

              Citation : Baryum


              car logiquement x et y pointe sur le même objet en memoire qui est 123456789



              Non, 123456789 n'est pas l'objet mais la valeur de l'objet. Même sans prendre des entiers très grands, l'interpréteur semble placer des entiers identiques à des emplacements mémoire différent, par exemple

              >>> 1000 is 10*100
              False
              >>> 1000 == 10*100
              True
              >>>
              


              Idem pour des immutables comme des chaînes.


              Moralement, la fonction is permet de savoir si deux objets sont à la même adresse-mémoire. À mon avis, l'usage de is est très limité. Si tu fouilles du code-source professionnel, tu verras que l'usage absolument écrasant de is est celui-ci : spam is None. Tu pourras rencontrer des choses du genre spam is True, spam is integer. Je serais curieux de savoir si un objet peut s'évaluer à None sans être l'objet None.
              • Partager sur Facebook
              • Partager sur Twitter
                26 novembre 2011 à 13:00:01

                Oui je me suis mal exprimé je voulais dire qu'ils pointent sur la meme adresse en memoire.
                En conclusion je vais surtout me servir de is dans is None/ is not None
                • Partager sur Facebook
                • Partager sur Twitter
                Anonyme
                  26 novembre 2011 à 15:52:04

                  type(objet) is type
                  >>> 1 is int
                  False
                  >>> type(1) is int
                  True
                  
                  • Partager sur Facebook
                  • Partager sur Twitter
                    26 novembre 2011 à 17:00:12

                    Citation : PsycoPy

                    type(objet) is type

                    >>> 1 is int
                    False
                    >>> type(1) is int
                    True
                    

                    Mieux vaut utiliser isinstance(variable, type).
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Anonyme
                      26 novembre 2011 à 17:19:59

                      En règle générale, oui. Mais dans certains cas isinstance ne se justifie pas.

                      def flatten(ls):
                          if type(ls) is not list:
                              return [ls]
                          if not ls:
                              return ls
                          return flatten(ls[0]) + flatten(ls[1:])
                      


                      Ici, seul le type list est vérifié, ainsi pour gagner en performance la fonction type est utilisé. Bien plus rapide.

                      PS: Je ne sais plus d'où sort ce code c'est dans une des source de matplotlib que Candide avait sorti pour corriger une fausse idée que je me faisais sur les pratiques courantes en Python... :-°
                      • Partager sur Facebook
                      • Partager sur Twitter
                      Anonyme
                        26 novembre 2011 à 17:44:40

                        if not isinstance(ls, list)
                        


                        C'est pas correct?

                        Pourtant t'as une fonction et une comparaison contre une seule fonction.

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Anonyme
                          26 novembre 2011 à 17:52:24

                          En fait, isinstance va plus loin en testant si l'objet n'est pas d'un type fils des types qu'on lui passe en argument, ce qui le rend assez lent quand on a pas besoin de vérifier ce dernier point.
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Anonyme
                            26 novembre 2011 à 17:56:21

                            Tu vas dire que je suis embêtant aujourd'hui avec ma PEP8, mais elle stipule

                            Citation : PEP 8

                            Object type comparisons should always use isinstance() instead
                            of comparing types directly.

                            Yes: if isinstance(obj, int):

                            No: if type(obj) is type(1):

                            • Partager sur Facebook
                            • Partager sur Twitter
                            Anonyme
                              26 novembre 2011 à 18:09:20

                              La PEP8 donne des conventions pour les généralités, mais dans certains cas particuliers c'est différent. :p
                              • Partager sur Facebook
                              • Partager sur Twitter
                                26 novembre 2011 à 18:11:58

                                Citation : PsycoPy

                                type(objet) is type

                                >>> 1 is int
                                False
                                >>> type(1) is int
                                True
                                




                                Et pourquoi utiliser is plutôt que == qui me semblerait plus adapté (on ne cherche pas à comparer l'identité d'objets-type) ?

                                Quoi qu'il en soit, il semblerait que == type( soit plus utilisé que is type(, à vue d'oeil de l'ordre de 50% (test effectué sur quelques dizaines de milliers de fichiers Python).



                                Citation : fred1599

                                Tu vas dire que je suis embêtant aujourd'hui avec ma PEP8, mais elle stipule

                                Citation : PEP 8

                                Object type comparisons should always use isinstance() instead
                                of comparing types directly.

                                Yes: if isinstance(obj, int):

                                No: if type(obj) is type(1):





                                De toute façon, le typage en production Python est mal vu, cf. par exemple Martelli qui dit


                                Type-checking ishardly ever appropriate
                                in production Python code because it interferes with polymorphism.
                                (...)isinstance(x,atype) is a lesser
                                evil than type(x) is atype, since at least it accepts an x that is an
                                instance of any subclass of atype, not just a direct instance of atype
                                itself.


                                Mais bon, là on s'éloigne de la question initiale.



                                • Partager sur Facebook
                                • Partager sur Twitter
                                Anonyme
                                  26 novembre 2011 à 18:19:11

                                  Citation : Martelli

                                  Type-checking ishardly ever appropriate
                                  in production Python code because it interferes with polymorphism.
                                  (...)isinstance(x,atype) is a lesser
                                  evil than type(x) is atype, since at least it accepts an x that is an
                                  instance of any subclass of atype, not just a direct instance of atype
                                  itself.



                                  Il dit bien que c'est tout de même moins mauvais :)

                                  Et encore comme Candide l'a fait comprendre précédemment, la comparaison de types en python, c'est un peu de la c.....e en barre, il suffit d'utiliser le paradigme EAFP.
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    26 novembre 2011 à 18:28:23

                                    Citation : candide

                                    Non, 123456789 n'est pas l'objet mais la valeur de l'objet. Même sans prendre des entiers très grands, l'interpréteur semble placer des entiers identiques à des emplacements mémoire différent, par exemple

                                    >>> 1000 is 10*100
                                    False
                                    >>> 1000 == 10*100
                                    True
                                    >>>
                                    



                                    Idem pour des immutables comme des chaînes.


                                    Visiblement pour les entiers c'est 256 la valeur limite. Mais il y a des subtilités :
                                    >>> x = 256
                                    >>> y = 256
                                    >>> x is y
                                    True
                                    >>> x = 257
                                    >>> y = 257
                                    >>> x is y
                                    False
                                    >>> x, y = 256, 256
                                    >>> x is y
                                    True
                                    >>> x, y = 257, 257
                                    >>> x is y
                                    True
                                    

                                    J'ai pas trouvé de documentation là-dessus, mais c'est pas si important de toute façon.
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Anonyme
                                      26 novembre 2011 à 18:47:59

                                      Citation

                                      Et pourquoi utiliser is plutôt que == qui me semblerait plus adapté (on ne cherche pas à comparer l'identité d'objets-type) ?

                                      À part pour des raisons de performance je ne sais pas.
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        26 novembre 2011 à 18:56:29

                                        Citation : PsycoPy

                                        Citation

                                        Et pourquoi utiliser is plutôt que == qui me semblerait plus adapté (on ne cherche pas à comparer l'identité d'objets-type) ?

                                        À part pour des raisons de performance je ne sais pas.



                                        Ce serait plus performant ? franchement à mon avis c'est Peanuts. Mais surtout ce qui me gêne c'est que les sémantiques de == et is ne sont pas les mêmes. Python étant un langage de haut niveau, en principe tu n'a pas à utiliser is ni id qui refèrent à une abstraction des adresses-machine des objets. À la rigueur pour id qui peut servir de hash mais pour is, je vois vraiment pas et j'ai eu beau chercher dans du code Python, le plus prégnant reste encore du type spam is None.

                                        Citation : fred1599


                                        Et encore comme Candide l'a fait comprendre précédemment, la comparaison de types en python, c'est un peu de la c.....e en barre, il suffit d'utiliser le paradigme EAFP.



                                        Disons que j'ai simplement rappelé ce que le sérail de Python conseille ; mais en même temps, il faut bien constater que dans du vrai code, y compris le code fourni dans l'implémentation officielle de Python, le typage est massivement utilisé donc je suis un peu sceptique devant ces conseils.


                                        Ça me fait penser à des discussions où certains prônent véhémentement l'abstinence de variables globales en C ou du goto alors qu'il est manifeste que dans du code reconnu de qualité, il en est fait usage, parfois massivement. Donc, je pense qu'il faudrait affiner les analyses en précisant dans quelles circonstances, des utilisations habituellement marginales s'avèrent utiles voire indispensables.
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        Anonyme
                                          26 novembre 2011 à 19:11:27

                                          Citation

                                          il faut bien constater que dans du vrai code, y compris le code fourni dans l'implémentation officielle de Python, le typage est massivement utilisé donc je suis un peu sceptique devant ces conseils.



                                          Tu peux être plus explicite?

                                          Python utilise le duck typing, il n'a pas besoin de faire de vérification de type étant donné qu'il connaît déjà le type utilisé.

                                          >>> a = 5
                                          >>> a +"coucou"
                                          Traceback (most recent call last):
                                            File "<pyshell#2>", line 1, in <module>
                                              a +"coucou"
                                          TypeError: unsupported operand type(s) for +: 'int' and 'str'
                                          


                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          Anonyme
                                            26 novembre 2011 à 19:18:03


                                            ls = [1, 2, 3, 'a', 'b', 'c']
                                            
                                            for i in range(1, 8):
                                                ls = [ ls[:]  for _ in range(i * 2) ]
                                            
                                            import time
                                            
                                            def test(f, ls):
                                                t = time.time()
                                                _ = f(ls[:])
                                                t = time.time() - t
                                                print(t)
                                            
                                            def flatten(ls):
                                                if type(ls) is not list:
                                                    return [ls]
                                                if not ls:
                                                    return ls
                                                return flatten(ls[0]) + flatten(ls[1:])
                                            
                                            def flatten2(ls):
                                                if not isinstance(ls, list):
                                                    return [ls]
                                                if not ls:
                                                    return ls
                                                return flatten2(ls[0]) + flatten2(ls[1:])
                                            
                                            def flatten3(ls):
                                                if type(ls) != list:
                                                    return [ls]
                                                if not ls:
                                                    return ls
                                                return flatten3(ls[0]) + flatten3(ls[1:])
                                            
                                            test(flatten, ls)
                                            test(flatten2, ls)
                                            test(flatten3, ls)
                                            


                                            7.484758138656616
                                            8.262046813964844
                                            8.011226892471313

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            Anonyme
                                              26 novembre 2011 à 19:22:01

                                              Au risque d'avoir une réponse erronnée, sachant que is est réservé à la comparaison d'id
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                26 novembre 2011 à 19:57:17

                                                Citation : PsycoPy


                                                7.484758138656616
                                                8.262046813964844
                                                8.011226892471313



                                                Oui et non.
                                                [dentuk@myhost ~]$ python3 /tmp/a.py
                                                10.393637895584106
                                                11.544962882995605
                                                11.225746870040894
                                                [dentuk@myhost ~]$ python2 /tmp/a.py
                                                9.24049091339
                                                10.7557280064
                                                9.17543792725
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                Anonyme
                                                  26 novembre 2011 à 20:04:38

                                                  Citation

                                                  Au risque d'avoir une réponse erronnée, sachant que is est réservé à la comparaison d'id


                                                  Pas de risque d'erreur.

                                                  >>> ls = [1, 2, 3]
                                                  >>> type(ls)(ls + [4])
                                                  [1, 2, 3, 4]
                                                  >>> id(_)
                                                  3074129292
                                                  >>> id(ls)
                                                  3074434828
                                                  >>> id(type(ls)), id(list)
                                                  (137336256, 137336256)
                                                  


                                                  @Dentuk: En effet, je n'ai testé qu'avec Py3k...

                                                  # Python 2
                                                  7.25831508636
                                                  8.339812994
                                                  7.67251205444
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    26 novembre 2011 à 21:45:17

                                                    Citation : fred1599


                                                    Tu peux être plus explicite?




                                                    Regarde le code-source Python de pratiquement n'importe quel module écrit en Python, il contient du type ou du isinstance, regarde par exemple random.py, sets.py, decimal.py, copy.py (lourdement typé), fractions.py. Même un module aussi anodin que calendar.py utilise isinstance :


                                                    if isinstance(i, slice):
                                                                return [f(self.format) for f in funcs]
                                                    



                                                    Et idem dans du code autre que celui de python.org.
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                    Anonyme
                                                      26 novembre 2011 à 22:04:50

                                                      Citation

                                                      Regarde le code-source Python de pratiquement n'importe quel module écrit en Python, il contient du type ou du isinstance, regarde par exemple random.py, sets.py, decimal.py, copy.py (lourdement typé), fractions.py. Même un module aussi anodin que calendar.py utilise isinstance



                                                      Je dis pas que dans tous les cas il faut éviter isinstance, des fois il n'y pas trop le choix non plus pour éviter le plantage du code.
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        26 novembre 2011 à 22:40:17

                                                        Citation : fred1599



                                                        Je dis pas que dans tous les cas il faut éviter isinstance, des fois il n'y pas trop le choix non plus pour éviter le plantage du code.



                                                        Un examen de 25490 fichiers Python donne 4097 fichiers qui utilisent isinstance environ 16%. Ce n'est pas marginal.
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          28 novembre 2011 à 13:01:00

                                                          Citation : Baryum


                                                          En conclusion je vais surtout me servir de is dans is None/ is not None




                                                          C'est d'ailleurs ce que préconisent les experts sur le forum usenet de Python. Les autres usages sont rares.
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter

                                                          Quand utiliser "is"/"is not"

                                                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                          • Editeur
                                                          • Markdown