Saisie texte en temps limité
Résolumamiemando Messages postés 33443 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 19 décembre 2024 - 2 sept. 2024 à 12:37
- Saisie texte en temps limité
- Blocage agriculteur carte en temps réel - Accueil - Transports & Cartes
- Transcription audio en texte word gratuit - Guide
- Renommer plusieurs fichiers en même temps - Guide
- Excel cellule couleur si condition texte - Guide
- Mettre un texte en majuscule - Guide
3 réponses
Modifié le 30 août 2024 à 15:10
Bonjour
Plusieurs recommandations préalables.
- Essaye de garder un sujet par discussion. Ici ta question est double puisque tu demandes de l'aide sur le module threading et une revue de code. Essaye d'être aussi spécifique que possible.
- Comme le souligne PierrotLeFou (voir #2), il faut alors construire un exemple minimal qui met en évidence le problème avant d'exposer ton problème.
- Pense à mettre le code en forme (cf ton premier message que j'ai remis en forme + le lien en fin de message).
Correction du bug
Explication du bug : quand le chronomètre expire, le fil d'exécution principale est toujours bloqué sur input.
Solution : Tu peux utiliser la technique proposée dans cette discussion, j'ai testé ça fonctionne :
import selectors import sys def main(): sel = selectors.DefaultSelector() sel.register(sys.stdin, selectors.EVENT_READ) print("Enter passcode: ", end='') sys.stdout.flush() pairs = sel.select(timeout=5) if pairs: passcode = sys.stdin.readline().strip() print('you entered:', passcode) else: print('\ntimed out') if __name__ == '__main__': main()
Conseils généraux
Je te renvoie aux suggestions faites par yg_be et PierrotLeFou (voir #1 et #2) :
- Regarde l'état des variables à l'aide de print. Pour des cas plus avancés, le module pdb peut t'aider. Dans des cas encore plus compliqués, tu peux aussi regarder logging. Mais à ce stade, utiliser print suffit.
- De plus, c'est souvent une bonne idée de prévoir une suite de tests pour vérifier qu'une fonction fait ce qui faut (notamment dans les cas limites). Une bonne idée est d'utiliser pytest.
- Tu devrais utiliser un outil comme flake8 qui te permettra de respecter les conventions de codage python et voir quelques erreurs de programmation. En outre, jeu_fin déclare deux variables corps_plein et corps_vide qui ne servent pas. Hormis les lignes trop longues, j'ai corrigé ton code en conséquence dans le message initial.
Revue du code
Je n'ai pas remarqué de bug à part la partie concernant l'appel à isdigit (voir plus loin). Par contre, tu peux améliorer le design et la robustesse de ton code.
Dans pendu
Robustesse :
- Le nombre d'essais (variable i) devrait varier de 0 à len(corps_plein).
- Tu ne devrais pas imposer de taper de taper en minuscule ou majuscule, simplement faire la conversion dans ton code.
- Le test isdigit n'est pas suffisant car il autorise la saisie d'un chiffre, il faudrait plutôt contrôler ainsi :
from pprint import pformat def is_letter(c) -> True: c = c.lower() return ( len(c) == 1 and 'a' <= c <= 'z' ) def test_is_letter(): for (c, expected) in { "": False, "AB": False, "B": True, "c": True, "1": False, "%": False }.items(): obtained = is_letter(c) print(f"is_letter('{c}') == {obtained}") assert obtained == expected, pformat(locals()) test_is_letter()
Design : Concernant le chrono, yu peux améliorer un peu le design et l'appel de cette fonction
import time from random import randint from functools import partial import threading stop_event = threading.Event() def chrono(duration: int = 30, step: int = 10): for i in range(0, duration): if stop_event.is_set(): return time.sleep(step) if i % step == 0: print(f"\nIl reste {duration - i} secondes") print("Temps écoulé !") stop_event.set() def jeu_juste_prix(): stop_event.clear() chrono_thread = threading.Thread(target=partial(chrono, duration=10, step=2)) chrono_thread.start() just_prize = randint(1, 2000) player = 0 while not stop_event.is_set(): try: player = int(input("Je pense que le nombre est ")) if player == just_prize: print("bravo vous avez trouvé le juste prix") stop_event.set() chrono_thread.join() return True elif player < 1 or player > 2000: print("Vous devez rentrez un nombre entre 1 et 2000") elif player > just_prize: print("C'est moins") elif player < just_prize: print("C'est plus") except ValueError: print("Vous devez rentrez un nombre") chrono_thread.join() print("return False") return False jeu_juste_prix()
Dans le programme principal
Modularité : Ton code commence à être un peu long pour un fichier. Tu devrais faire un fichier par jeu (par exemple shi_fu_mi.py, juste_prix.py et pendu.py), et un fichier principal (disons main.py) qui importe chacun des jeux comme suit :
from shi_fu_mi import shi_fu_mi from juste_prix import jeu_juste_prix from pendu import pendu # Reste du code
Design :
- Il n'est pas très élégant d'enchaîner les jeux comme tu le fais, tu pourrais faire une liste de fonction, où chaque fonction est un jeu, et itérer sur cette liste en faisant quelque chose dans ce genre :
jeux = [shi_fu_mi, jeu_juste_prix, pendu] progression = 0 while progression < len(jeux): jeu = jeux[progression] gagne = jeu() if gagne: progression += 1 else: print(f"Dommage, vous avez perdu au {jeu.__name__}") break if progression == len(jeux): print("Bravo") else: print("Dommage !")
- Les mots aléatoire du pendu devraient être un paramètre de la fonction pendu. Ainsi tu te laisses la possibilité de charger par la suite tes mots depuis un fichier texte tiers (par exemple /usr/share/dict/french sous Linux).
- Si tu ajoutes des paramètres aux fonctions de jeu, dans l'extrait de code précédent, utilise partial pour que les paramètres soient précisés au moment de construire jeux (ainsi l'appel du jeu courant se fait sans paramètre).
- Il faut idéalement se passer de variables globales. La seule exception concerne les "constantes" (que j'ai renommées en capitales afin de se conformer aux conventions python).
- Garde aussi peu de code que possible en dehors d'une fonction. Ton programme principal devrait être déporté dans une fonction main, et la seule chose en dehors des fonctions devrait être les déclarations des constantes et l'appel à main. Ainsi, tu es sûr que chaque fonction s'en tient aux constantes et aux variables reçu en paramètre (pas de risque de lire une variable globale).
Bonne chance
29 août 2024 à 20:24
bonjour, quelle technique utiles-tu pour débugger, en dehors de demander de l'aide?
Une technique habituelle, et très simple, c'est d'ajouter des print(), afin de comprendre le comportement du code que tu as écrit.
30 août 2024 à 21:38
Bonjour,
j'utilise les point d'arrêt avec le débugger de Visual Studio Code. ET quand je n'arrive pas à me débugger je demande à chat gpt de trouver le problème et de m'expliquer ce qui ne marchait pas. Or, ici chat gpt n'arrivais pas à me débugger.
J'ai essayer de mettre un print si la fonction me return true. Or, la fonction ne m'affichait pas le print en question
As-tu seulement testé le threading avec une fonction très simple qui ne fait que ça?
30 août 2024 à 21:41
Bonjour,
je ne suis pas sûr de bien comprendre votre remarque. Le threading marche sur la fonction juste_prix toute seule. Il se lance en parallèle du jeu et se stop quand on trouve la valeur. Il fonctionne bien. Le problème c'est que quand il arrive au bout sans qu'on ai trouvé, la fonction juste_prix ne return pas False et donc engendre le problème dans la fonction jeu_fin.
30 août 2024 à 21:48
Bonjour,
Merci pour tous ces bons conseils. Je suis désolé pour toutes mes erreurs, je suis novice dans la programmation et c'était la première fois que j'écrivais dans un forum pour de l'aide. Je vais tâcher d'appliquer tous vos bons conseils
2 sept. 2024 à 12:37
Aucun problème, on est tous là pour progresser :-) Est-ce que tu as toutes tes réponses sur le problème initial ? Si oui, merci de basculer le sujet en résolu. Tu peux également upvoter la ou les réponses qui t'ont aidées.