Partage
  • Partager sur Facebook
  • Partager sur Twitter

Les nouveautés de Python 3.10.0rc2

Que penser du patern matching ?

    27 septembre 2021 à 23:20:42

    Salut !

    Vous le savez peut-être, python 3.10 est sur le point de débarquer en amenant une grande nouveauté pour le langage : du patern matching avec une structure de la forme match case. Comme certains l'ont peut-être remarqué (avec les type hint par exemple) je suis un fanatique de ce genre de gadget syntaxique. J'ouvre ce sujet pour évaluer quelle réputation cette feature a sur Open Classrooms, ou, si c'est trop tôt, ce que vous en attendez, ce que vous craignez, ect... que vous soyez confirmé ou moins expérimenté bien sûr.

    Il est d'ors et déjà possible de tester tout ça (depuis quelques temps d'ailleurs) en se procurant la nouvelle version ici : https://pythoninsider.blogspot.com/2021/09/python-3100rc2-is-available.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+PythonInsider+%28Python+Insider%29 . Je pense que c'est un très bon ajout, qui permet de gérer élégamment énormément de situations, pour peu que l'on résiste à la tentation d'en mettre partout à la place de chaque condition. C'est tout de même dommage d'ajouter des mots clés.

    Par ailleurs, j'ai remarqué un autre ajout plus anecdotique :

    >>> uwu = 42
    >>> owu
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'owu' is not defined. Did you mean: 'uwu'?

    (Celui-là n'apparaît pas dans le résumé de python insider je crois).

    Pour finir, je ne sais pas pourquoi, pythonpool.com proclame que l'ajout de patern matching va permettre la surcharge de fonctions. C'est faux, en tout cas pour l'instant.

    • Partager sur Facebook
    • Partager sur Twitter

    typage structurel ftw

    Anonyme
      28 septembre 2021 à 0:22:50

      Pas le temps de maitriser les changements de la 2.7 qu'on est déjà à la 3.10 ! ^^ Un truc que je reprocherais à Python, ça évolue trop vite pour un usage amateur, je n'imagine pas la charge de travail que ça doit être pour un pro qui veut être à jour sur tous les langages de programmation dont il a besoin !!!

      Aucune idée de ce que c'est que le match et le case, j'ai beau regardé les exemples de ce site : http://lepython.com/python-3-10-quelles-nouveautes/ je me demande à quoi ça va me servir. 

      Ca permet d'éviter un try except, entre autre, c'est ça ? (Si c'est ça, c'est assez limité)

      def func(X):  # X = (x, y, z)
          # point est un tuple de la forme (x, y) 
          match point:
              case (0, 0):
                  print("Origine")
              case (0, y):
                  print(f"Y={y}")
              case (x, 0):
                  print(f"X={x}")
              case (x, y):
                  print(f"X={x}, Y={y}")
              case _:
                  raise ValueError("n'est pas un point")

      L'équivalent serait ce qui suit n'est-ce pas ?

      def func2(X):
      	try:
      		x,y = (X[0],X[1])
      		if (x,y) == (0,0):
      			print('Origine')
      		elif not x and y:
      			print(f'Y={y}')
      		elif x and not y:
      			print(f'X={x}')
      		else:
      			print(f'X={x}, Y={y}')
      	except:
      		raise ValueError("n'est pas un point")

      Une ligne de gagnée =/


      -
      Edité par Anonyme 28 septembre 2021 à 0:41:42

      • Partager sur Facebook
      • Partager sur Twitter
        28 septembre 2021 à 1:22:45

        Je me demande ce que ça donnerait si j'avais 25 cas différents du point devue performance.
        Ça devrait être plus puissant que le switch de C ou C++.
        Jusqu'ici, je me débrouillais avec les dictionnaires, mais il faut les construire.
        Ça va me prendre un peu de recul pour évaluer le gain de cette possibilité.
        J'espère que je pourrai passer plus facilement à la version 3.10 que j'essaie de le faire pour passer de 3.9.6 à 3.9.7 ...
        Il me semble que les ajouts sont "relativement" bien documentés dans la page de download du site officiel de Python.
        • Partager sur Facebook
        • Partager sur Twitter

        Le Tout est souvent plus grand que la somme de ses parties.

          28 septembre 2021 à 9:25:09

          @ErispoeLeNarvalo pas exactement, tes deux fonctions ne donneraient pas la même chose pour X="ab" ou X=(1,2,3) par ex (je ne compte pas l'erreur du match point au lieu de match X :p)

          match case (0, y):

          ça vérifie le type et la longueur, il n'y a pas de besoin de try, c'est équivalent à:

          if isinstance(point, (list, tuple)) and len(point) == 2 and not point[0]:

          Voici un équivalent pour le total :

          def func(X):
              if isinstance(X, (list, tuple)) and len(X) == 2:
                  x, y = X
                  if (x, y) == (0, 0):
                      print("Origine")
                  elif not x:
                      print(f"Y={y}")
                  elif not y:
                      print(f"X={x}")
                  else:
                      print(f"X={x}, Y={y}")
              else:
                  raise ValueError("n'est pas un point")
          


          Toujours une ligne de gagnée, mais c'est un truc assez puissant ya de meilleurs exemples dans la PEP 622

          -
          Edité par thelinekioubeur 28 septembre 2021 à 9:29:09

          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            28 septembre 2021 à 16:49:55

            @thelinekioubeur Pas vraiment non plus len(X) peut être supérieur ou égale à 2, non ?

            def func(X):  # X = (x, y, z)

            X="ab" ou X=(1,2,3)

            Ma func2 attend une liste ou un tuple comme la fonction avec le match/case, pas besoin de couvrir l'intégralité des possibilités. Sinon ça soulève une exception, nan ?

            Edit :
            isinstance je l'utilise jamais, non plus :euh:, mais plutôt : 

            type([1,2,3]) == (list or tuple)

            -
            Edité par Anonyme 28 septembre 2021 à 17:07:43

            • Partager sur Facebook
            • Partager sur Twitter
              28 septembre 2021 à 17:02:14

              Non si la len n'est pas 2 ça matche pas.

              Ta func2 elle attend n'importe quelle sequence de longueur supérieure ou égale à 2.

              Sur ta première func  "ab" et (1,2,3) ne matchent avec rien donc ça lève le valuerror.

              Avec ta func2, "ab" donnera "X=a, Y=b" et (1,2,3) donnera "X=1, Y=2"

              Bref faut lire la pep622, et faire des tests

              -
              Edité par thelinekioubeur 28 septembre 2021 à 17:03:33

              • Partager sur Facebook
              • Partager sur Twitter
                4 octobre 2021 à 18:10:37

                Python 3.10 était censé être disponible aujourd'hui. Ça ne semble pas êttre le cas.
                Est-ce une bonne idée que d'installer une nouvelle version le jour de son lancement officiel?
                Je l'ai fait avec Python 3.9.6 et je n'ai pas eu de problème.
                J'ai bien hâte de voir ce que donne le match case
                • Partager sur Facebook
                • Partager sur Twitter

                Le Tout est souvent plus grand que la somme de ses parties.

                  4 octobre 2021 à 19:12:16

                  sans doute une question de fuseau horaire :lol:
                  • Partager sur Facebook
                  • Partager sur Twitter
                    4 octobre 2021 à 20:22:25

                    Ça fait un moment qu'on peut tester le match case sur 3.10.0rc2 ;)
                    • Partager sur Facebook
                    • Partager sur Twitter
                      5 octobre 2021 à 5:06:05

                      Je suis en retard sur vous, semble-t-il :)
                      J'ai tout de même trouvé le truc pour l'équivalent du default de C ou C++
                      -
                      a = input(">")
                      match a:
                          case '1':
                              print("cas un")
                          case '2':
                              print("cas deux")
                          case _:
                              print("autre")
                      -
                      Autre truc intéressant (pour moi).
                      Le paramètre  "strict"  de zip qui donne une erreur si les listes ne sont pas de même longueur.

                      Comment faire des comparaisons de performances?

                      Pour simuler un switch, j'utilise un dictionnaire.

                      Ou bien devrais-je comparer à des if elif ... else en cascade?

                      Le dictionnaire sera nettement plus rapide et le if elif sera plus lent?

                      edit:
                      Voici un petit générateur de code pour comparer le match case avec les if elif. J'en ai fait autant pour le dictionnaire.
                      Je vous laisse le tester, mais je peux dire que c'est désastreux pour le match case
                      L'intérêt sera dans la clarté et la flexibilité.
                      -
                      file=open("am.py", "w")
                      n=1000
                      file.write("from time import perf_counter\n")
                      file.write(f"n={n}\n")
                      file.write("begin=perf_counter()\n")
                      file.write("for _ in range(1, n+1):\n")
                      file.write(" "*4+"for i in range(1, n+1):\n")
                      file.write(" "*8+"match i:\n")
                      for i in range(1, n+1):
                          file.write(" "*12+f"case {i}: b=i\n")
                      file.write("print(round(perf_counter()-begin, 3), 'secondes')\n")
                      file.write("begin=perf_counter()\n")
                      file.write("for _ in range(1, n+1):\n")
                      file.write(" "*4+"if i==1: b=i\n")
                      for i in range(2, n+1):
                          file.write(" "*4+f"elif i=={i}: b=i\n")
                      file.write("print(round(perf_counter()-begin, 3), 'secondes')\n")

                      -
                      Edité par PierrotLeFou 5 octobre 2021 à 8:00:16

                      • Partager sur Facebook
                      • Partager sur Twitter

                      Le Tout est souvent plus grand que la somme de ses parties.

                        5 octobre 2021 à 8:18:01

                        Le match case n'est pas fait pour faire ça :lol:  Puis là il te manque une boucle pour tes elifs, c'est le match case qui est plus rapide !

                        Pour comparer les perfs, je dirais qu'il vaut mieux le faire avec un match case de quelques lignes, en le relançant n fois avec timeit.timeit.

                        Mais note que:

                        - Pour les use cases la différence de perfs sera négligeable

                        - L'intérêt du match case ce sont les use cases où sa syntaxe permet de simplifier par rapport aux elifs (voir les exemple de la PEP 622 encore une fois)


                        Sinon, 3.10 est sorti :magicien:

                        -
                        Edité par thelinekioubeur 5 octobre 2021 à 8:20:10

                        • Partager sur Facebook
                        • Partager sur Twitter
                          5 octobre 2021 à 15:23:53

                          Mea culpa ... j'avais une double boucle pour tester le dictionnaire et je l'ai éliminé.
                          J'ai bien trouvé python 3.10 ...
                          Je suis sur Windows et j'utilise perf_counter pour mes évaluations de performances, c'est correct?
                          En effet, match case est plus rapide que if elif
                          • Partager sur Facebook
                          • Partager sur Twitter

                          Le Tout est souvent plus grand que la somme de ses parties.

                            5 octobre 2021 à 17:08:55

                            perf_counter c'est correct oui, juste je trouve timeit.timeit plus pratique
                            • Partager sur Facebook
                            • Partager sur Twitter
                              5 octobre 2021 à 18:19:03

                              Avec le dictionnaire, ce code devrait être correct:
                              Le désavantage du dictionnaire est qu'on ne peut pas exécuter n'importe quoi facilement.
                              J'ai déjà mis des fonctions comme valeurs, mais le nombre de paramètres était le même pour toutes.
                              -
                              dico=dict()
                              for i in range(1, n+1):
                                  dico[i]=i
                              begin=perf_counter()
                              for _ in range(1, n+1):
                                  for i in range(1, n+1):
                                      b=dico[i]
                              print(round(perf_counter()-begin, 3), 'secondes')
                              -
                              10.222 secondes                                                                                                         
                              0.088 secondes

                              edit:

                              J'ai oublié de dire que le premier temps est toujours celui des martch case

                              -
                              Edité par PierrotLeFou 5 octobre 2021 à 18:21:53

                              • Partager sur Facebook
                              • Partager sur Twitter

                              Le Tout est souvent plus grand que la somme de ses parties.

                              Les nouveautés de Python 3.10.0rc2

                              × 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