Forum Programmation.python Python: Return value not found in function

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
-4
30
mar.
2021

Salut @everyone!

Je galère un peu … Je ne suis pas un pro de python, je débogue un programme chatboot. J’ai mon algorithme, ma fonction build_answer effectue une recherche pour trouver "order_info" dans message, question, history, si après order_info n’a pas été trouvé, alors je voudrais un retour "Not found".

L’aide sera vraiment la bienvenue.

Voici où je suis et ma progression …

    def build_answer(shop,order_info,message,questions,history,is_buffalo):

        questions_2 = ["info_not_found","none"]
        history_line = None

        # CASE 1: if the customer has already a question
        for j in range(len(history)):
            if (message["email"] in history[j]):
                if history[j][2] == "no": # Question and then customer_id
                    questions_2 = eval(history[j][3].replace("$",","))
                    if order_info != {}:
                        response, answer_id = detect_response(shop,questions_2,order_info,message,history)
                        history[j][2] = order_info["customer_id"]

                    elif "not_customer" in questions and "status" in questions_2:
                        question_2 = ["status","not_customer"]
                        order_info_2 = {"status":"none","time":400,"order_time":400}
                        response, answer_id = detect_response(shop,questions_2,order_info_2,message,history)

                    else:
                        response = "/ALERT I could not find info on this customer"
                        answer_id = "s9"

                elif order_info != {}:
                    response, answer_id = detect_response(shop,questions,order_info,message,history)
                else:
                    response = "/ALERT I could not find info on this customer"
                    answer_id = "s9"

                answer_ids = list(eval(history[j][4].replace("$",",")))
                if answer_id not in answer_ids:
                    answer_ids.append(answer_id)
                else:
                    return "/ALERT This customer often asks me the same question", "/ALERT"
                history[j][4] = str(answer_ids)
                lst = []  #rebuild the file content
                for lst3 in history:
                    lst.append(",".join(lst3))
                cont = "\n".join(lst)
                file = open("shops/{}/history.csv".format(shop),"w")
                file.write(cont)
                file.close()
                return response, answer_id




        if order_info != {}:
            response, answer_id = detect_response(shop,questions,order_info,message,history)
            info = order_info["customer_id"]

        else:
            order_info_2 = {"status":"none","time":400,"order_time":400}
            response, answer_id = detect_response(shop,questions_2,order_info_2,message,history)
            info = "no"
        # Build the file content
        answer_ids = []
        answer_ids.append(answer_id)
        if is_buffalo:
            shop = "BUFFALO"
        file = open("shops/{}/history.csv".format(shop),"a")
        content = "\n{},{},{},{},{}".format(message["email"],str(datetime.now())[:-7],info,str(questions).replace(",","`{mathjax} "),str(answer_ids).replace(",","`").replace("\r",""))
        if is_buffalo:
            content += ",{}".format(shop)
        file.write(content)
        file.close()
        return response, answer_id
  • # syntmk et miprotech223 sont sur un bateau...

    Posté par  . Évalué à 5.

    J'ai l'impression que ce programme chatbot a la chance d'avoir un tas de contributeurs.
    Un certain syntmk a déjà posté dans d'autres posts sur ce programme
    Il assure que les réponses reçues "m'ont été très utiles et ont permis de résoudre mon problème". Peut-être qu'il viendra te filer un coup de main !

  • # Moult remarques

    Posté par  (site web personnel) . Évalué à 9.

    Voici quelques retour sur ton code pour faire du code plus idiomatique (et donc plus court, lisible, simple et facile à débugger) :

    • Tu respectes PEP8 plutôt bien, mais dans les listes arguments (et les listes, les dictionnaires…) il faut un espace après les virgules.

    • Évite les index quand un itérateur fait le boulot:

            for j in range(len(history)):
                if (message["email"] in history[j]):
                    ...

    deviendrait:

            for history_info in history:
                if message["email"] in history_info:
                    ...
    • Les tests de listes/dictionnaires/tuples… vides peuvent être écrits de manière plus courte et performante:
        if order_info != {}:
          ...

    s'écrit plutôt :

        if order_info:
          ...
    • Utilise with pour la gestion des fichiers (c'est plus court et le fichier est fermé même en cas d'erreur)
        file = open(..., "w")
        file.write(cont)
        file.close()

    gagne à être écrit :

        with open(..., "w") as f:
            f.write(cont)
    • Pour les chemins de fichier utilise par exemple os.path.join() qui mettra le bon séparateur suivant la plateforme.

    • Les list comprehension c'est la vie:

        lst = []
        for lst3 in history:
           lst.append(",".join(lst3))
        cont = "\n".join(lst)

    peut s'écrire :

        lst = [",".join(h) for h in history]
        cont = "\n".join(lst)

    Qu'on simplifie alors en :

        cont = "\n".join([",".join(h) for h in history])

    Et avec la magie des generator expressions ça peut même être encore plus joli (les [] disparaissent):

        cont = "\n".join(",".join(h) for h in history)
    • Peu de chances que l'utilisation de eval() soit une bonne idée (surtout quand on manipule des données externes).

    Bon courage pour la suite !

    • [^] # Re: Moult remarques

      Posté par  . Évalué à 2. Dernière modification le 31 mars 2021 à 07:27.

      Salut,

      Et on retrouve la tendance à faire de longs pavés ;)

      Par exemple, tout ce qui est en dessous de :

              # Build the file content
              [...]
              return response, answer_id

      peut être isolé dans une fonction il me semble pour avoir :

              # Build the file content
              log_response(param1, param2) # mettre les paramètres nécessaires
              return response, answer_id

      Matricule 23415

      • [^] # Re: Moult remarques

        Posté par  . Évalué à 3.

        Salut, moi,

        D'ailleurs, c'est pas ça (trop tard pour éditer), ça serait plutôt :

                # Build the file content
                answer_ids = []
                answer_ids.append(answer_id)
                log_response(param1, param2) # mettre les paramètres nécessaires
                return response, answer_id

        D'où l'importance de ne pas faire de pavés…

        Matricule 23415

      • [^] # Re: Moult remarques

        Posté par  . Évalué à 3.

        Et idem pour le code au dessus :

                if order_info != {}:
                    response, answer_id = detect_response(shop,questions,order_info,message,history)
                    info = order_info["customer_id"]
        
                else:
                    order_info_2 = {"status":"none","time":400,"order_time":400}
                    response, answer_id = detect_response(shop,questions_2,order_info_2,message,history)
                    info = "no"

        peut devenir simplement :

                response, answer_id, info = prepare_response(paramA, paramB) # ajuster les params

        Matricule 23415

      • [^] # Re: Moult remarques

        Posté par  . Évalué à 3. Dernière modification le 31 mars 2021 à 07:53.

        Et encore même chose pour plus haut, je pense :

                for j in range(len(history)):
                    if (message["email"] in history[j]):
                        if history[j][2] == "no": # Question and then customer_id
                            questions_2 = eval(history[j][3].replace("$",","))
                            if order_info != {}:
                                response, answer_id = detect_response(shop,questions_2,order_info,message,history)
                                history[j][2] = order_info["customer_id"]
        
                            elif "not_customer" in questions and "status" in questions_2:
                                question_2 = ["status","not_customer"]
                                order_info_2 = {"status":"none","time":400,"order_time":400}
                                response, answer_id = detect_response(shop,questions_2,order_info_2,message,history)
        
                            else:
                                response = "/ALERT I could not find info on this customer"
                                answer_id = "s9"
        
                        elif order_info != {}:
                            response, answer_id = detect_response(shop,questions,order_info,message,history)
                        else:
                            response = "/ALERT I could not find info on this customer"
                            answer_id = "s9"
        
                        answer_ids = list(eval(history[j][4].replace("$",",")))
                        if answer_id not in answer_ids:
                            answer_ids.append(answer_id)
                        else:
                            return "/ALERT This customer often asks me the same question", "/ALERT"
                        history[j][4] = str(answer_ids)
                        lst = []  #rebuild the file content
                        for lst3 in history:
                            lst.append(",".join(lst3))
                        cont = "\n".join(lst)
                        file = open("shops/{}/history.csv".format(shop),"w")
                        file.write(cont)
                        file.close()
                        return response, answer_id

        peut devenir :

                for j in range(len(history)):
                    if (message["email"] in history[j]):
                        return handle_email(X, Y, Z) # toujours pareil...

        Ce qui donne la fonction :

           def build_answer(shop,order_info,message,questions,history,is_buffalo):
        
                questions_2 = ["info_not_found","none"]
                history_line = None
        
                for j in range(len(history)):
                    if (message["email"] in history[j]):
                        return handle_email(X, Y, Z) # toujours pareil...
        
                response, answer_id, info = prepare_response(paramA, paramB) # ajuster les params
        
                # Build the file content
                log_response(param1, param2) # mettre les paramètres nécessaires
                return response, answer_id

        Un peu plus clair, non ?

        Note : prendre aussi en compte les remarques précédentes

        Note 2 : les opérations de log peuvent être factorisées également… toujours même raison.

        Matricule 23415

  • # Ça veut dire quoi ?

    Posté par  . Évalué à 2. Dernière modification le 31 mars 2021 à 07:13.

    Salut,

    Qu'entend-tu par : je voudrais un retour "Not found" ?

    Lever une exception ?

    Je me posais déjà la question dans l'autre post, mais j'ai préféré y aller molo…

    Matricule 23415

    • [^] # Re: Ça veut dire quoi ?

      Posté par  . Évalué à 1. Dernière modification le 01 avril 2021 à 00:57.

      Je suis vraiment surpris, merci beaucoup pour votre temps pour votre aide ça me touche.

      Je commence à mieux comprendre …

      Oui, je voudrai lever une exception. S'il n'y a pas order_info dans message,questions,history que ça me renvoi en return "Not found" en signifiant dans le mail que order_info n'a pas été trouvé.

      Encore une fois merci à vous !

      • [^] # Re: Ça veut dire quoi ?

        Posté par  . Évalué à 2. Dernière modification le 01 avril 2021 à 07:10.

        Salut,

        Lorsqu'il y a un début de code, même non fonctionnel, que les remarques semblent être prises en compte, ça motive pour aider ;)

        Revenons-en à la question : lever une exception et un retour de fonction sont deux choses très différentes… voir ici pour la notion d'exception. Un retour "remonte" à la fonction appelante, une levée d'exception "remonte" la pile d'appel jusqu'à arriver à un traitement (bloc tryexcept …) ou interrompt le programme s'il n'y a pas de traitement.

        J'en profite pour ajouter aussi un autre commentaire : en général, je loggue (surtout pour débugguer) à l'entrée et à la sortie d'une fonction. Là, vous ne logguez qu'à la sortie, donc difficile de bien savoir où on est lors d'un bug.

        PS : il existe des modules de logging tout faits en python, mais ça peut être un point abordé plus tard.

        Matricule 23415

        • [^] # Re: Ça veut dire quoi ?

          Posté par  . Évalué à 1.

          Salut kaos,
          Votre aide m'est très précieuse. J'ai eu à résoudre quelques problèmes de la suite de ce chatboot grâce à vos explications …

          Voici ma fonction j'ai mis les exception. Est-ce bon ?

          def build_answer(shop, order_info, message, questions, history, is_buffalo):
              questions_2 = ["info_not_found", "none"]
              history_line = None
          
              for j in range(len(history)):
                  try:
                      if (message["email"] in history[j]):
                          return handle_email(questions_2, order_info, message, history)
          
                          response, answer_id, info = prepare_response(shop, questions, order_info, message,history)
                  except IOError:
                      print("Ordre_info Not found")
          
                  else:
                      print("Ordre_info Not found")
          
              # Build the file content
              answer_ids = [] ;
              answer_ids.append(answer_id);
          
              log_response(shop, questions_2, order_info, message, history)
          
              return response, answer_id
          
          • [^] # Re: Ça veut dire quoi ?

            Posté par  . Évalué à 2. Dernière modification le 01 avril 2021 à 12:24.

            Salut,

            Voici ma fonction j'ai mis les exception. Est-ce bon ?

            Malheureusement, pas vraiment :) Ce qui n'est pas grave en soi, il faut bien commencer par apprendre un jour avant d'être à l'aise.

            Pour lever une exception à un endroit donné, c'est le mot clef raise suivi de l'exception à lever qu'il faut utiliser. Ici, le bloc tryexcept … bloque la propagation à un niveau supérieur de l'exception IOError (et uniquement les exceptions de ce type, toutes les autres continuent de remonter la pile d'exécution). Je ne comprend pas l'intérêt du else.

            PS : je ne suis pas là pour dire ce qui est "bon" ou "mauvais" ;) juste conseiller ;)

            Matricule 23415

            • [^] # Re: Ça veut dire quoi ?

              Posté par  . Évalué à 2.

              Petit complément :

              Certes, tu n'as jamais écrit raise dans ton programme, mais il est écrit quelque part dans les appels que fait la fonction write, si ça peut t'aider à comprendre.

              Matricule 23415

            • [^] # Re: Ça veut dire quoi ?

              Posté par  . Évalué à 1.

              ah oui lol vous êtes un bon maître :)

              def build_answer(shop, order_info, message, questions, history, is_buffalo):
                  questions_2 = ["info_not_found", "none"]
                  history_line = None
              
                  for j in range(len(history)):
                      try:
                          if (message["email"] in history[j]):
                              return handle_email(questions_2, order_info, message, history)
              
                              response, answer_id, info = prepare_response(shop, questions, order_info, message,history)
                      except Raise :
                          print("Ordre_info Not found")
              
                  # Build the file content
                  answer_ids = [] ;
                  answer_ids.append(answer_id);
              
                  log_response(shop, questions_2, order_info, message, history)
              
                  return response, answer_id
              
              • [^] # Re: Ça veut dire quoi ?

                Posté par  . Évalué à 2.

                Plutôt pas, j'ai l'impression, sur le coup…

                Matricule 23415

                • [^] # Re: Ça veut dire quoi ?

                  Posté par  . Évalué à 1.

                  oups…
                  Je vous avoue que je suis un peu perdu :( .
                  Je dois me mettre à sur des cours plus approfondi sur python.
                  Merci pour votre aide :) !

                • [^] # Re: Ça veut dire quoi ?

                  Posté par  . Évalué à 1.

                  J'ai fais un return de mes paramètres après "except Raise :"

                  def build_answer(shop, order_info, message, questions, history, is_buffalo):
                      questions_2 = ["info_not_found", "none"]
                      history_line = None
                  
                      for j in range(len(history)):
                          try:
                              if (message["email"] in history[j]):
                                  return handle_email(questions_2, order_info, message, history)
                  
                                  response, answer_id, info = prepare_response(shop, questions, order_info, message,history)
                          except Raise :
                              print("Ordre_info Not found")
                              return handle_email(questions_2, order_info, message, history)
                  
                  
                      # Build the file content
                      answer_ids = []
                      answer_ids.append(answer_id)
                  
                      log_response(shop, questions_2, order_info, message, history)
                  
                      return response, answer_id
                  

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.