Programme de gestion des tâches en Python
J'ai fait un programme simple en Python
- stocke les tâches dans le fichier
- permet à l'utilisateur de les gérer.
Je suis intéressé si ma mise en œuvre est efficace et pourrais-je faire mieux. Je ne suis pas sûr que le chargement de toutes les données du fichier vers la mémoire et leur enregistrement à nouveau dans le fichier soit un bon moyen de mettre en œuvre des tâches d'enregistrement de liste.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
CHOICE_LIST_TASKS = 1
CHOICE_ADD_TASK = 2
CHOICE_REMOVE_TASK = 3
CHOICE_QUIT = 4
def read_int(prompt='> ', errmsg='Invalid number!'):
num = None
while num is None:
try:
num = int(input(prompt))
except ValueError:
print(errmsg)
return num
def display_menu():
print('What do you want to do?')
print('[1] List all tasks')
print('[2] Add a new task')
print('[3] Delete task')
print('[4] Quit')
choice = None
file = None
if not os.path.exists('tasks'):
file = open('tasks', 'w+')
else:
file = open('tasks', 'r+')
tasks = []
for line in file.readlines():
tasks.append(line.strip())
while choice != CHOICE_QUIT:
display_menu()
choice = read_int()
if choice == CHOICE_LIST_TASKS:
if len(tasks) == 0:
print('Task list is empty!')
else:
print('Tasks:')
for x in tasks:
print(x)
elif choice == CHOICE_ADD_TASK:
desc = input('Which task do you want to do? ')
index = tasks.append(desc)
print('Successfully added a new task!')
elif choice == CHOICE_REMOVE_TASK:
if len(tasks) == 0:
print('Task list is empty!')
else:
for x in tasks:
print(tasks.index(x), x)
index = read_int('Which task do you want to delete? ')
try:
tasks.pop(index)
print('Successfully deleted task!')
except IndexError:
print('Please enter proper task number')
elif choice == CHOICE_QUIT:
print('Good bye!')
else:
print('Invalid choice!')
file = open('tasks', 'w+')
for x in tasks:
file.write(x + '\n')
Réponses
Commençons par le haut.
CHOICE_LIST_TASKS = 1
CHOICE_ADD_TASK = 2
CHOICE_REMOVE_TASK = 3
CHOICE_QUIT = 4
Il est clair pour moi que vous voulez créer des variables et leur attribuer certains nombres entiers afin de ne pas avoir à utiliser de nombres magiques n'importe où, bravo à vous pour cela. Il existe une bien meilleure façon de mettre en œuvre cette idée en python
Énumérations: Enum
Énumérations en Python
Une énumération est un ensemble de noms symboliques
(membres) liés à des valeurs constantes uniques
créer un Enum
class Choices(Enum):
list_task = 1
add_task = 2
remove_task = 3
quit = 4
Cela semble déjà beaucoup plus clair que les variables globales aléatoires. Vous pouvez également parcourir l'énumération et afficher ses valeurs avec des noms .
print(Choices.add_task.name)
Ajouter une tâche
print(Choices.add_task.value)
1
Utiliser plus de fonctions
file = None
if not os.path.exists('tasks'):
file = open('tasks', 'w+')
else:
file = open('tasks', 'r+')
tasks = []
for line in file.readlines():
tasks.append(line.strip())
Pourquoi ne pouvons-nous pas déplacer cela dans une fonction appelée read_task_file()?
De cette façon, il est extrêmement clair pour moi, pour vous, pour vous après un an de lecture de projets anciens, et pour quiconque lira jamais ce code que ces quelques lignes de code liront le fichier de tâche . Sans cela, il faut lire attentivement le code et comprendre son objectif.
def read_task_file():
file = None
if not os.path.exists('tasks'):
file = open('tasks', 'w+')
else:
file = open('tasks', 'r+')
tasks = []
for line in file.readlines():
tasks.append(line.strip())
return tasks
maintenant obtenir les tâches est
tasks = read_task_file()
C'est exactement la même chose pour le prochain jeu de code, qui permettra à l'utilisateur d'entrer son choix afin que nous puissions l'exécuter.
La factorisation de la partie où nous lisons un choix de l'utilisateur et l'exécutons dans une fonction ressemblerait à
def read_task_choice():
display_menu()
choice = read_int()
if choice not in Choices._value2member_map_:
print("Invalid input! Please enter a correct choice\n")
read_task_choice()
Remarque: Choices._value2member_map_seront toutes les valeurs d'une énumération.
Cela semble déjà beaucoup plus propre! Nous éliminons le besoin de l'avoir dans une boucle où il vérifiera tous les cas, la fonction ne retourne que choicelorsqu'il y a une entrée valide.
Comme je l'ai dit, divisez le travail en fonctions et toutes au besoin. J'ai fait la même chose pour les 4 tâches principales (les 4 choix).
Répertorier les tâches
def list_tasks(tasks):
if len(tasks) == 0:
print("Task list is empty!")
return None
for i in range(len(tasks)):
print(f"{i} {tasks[i]}")
Ajouter une nouvelle tâche
def add_new_task(tasks):
return input("What task would you like to finish ?: ")
tasks.append(task)
Supprimer la tâche
def remove_task(tasks):
if len(tasks) == 0:
print("Task list is already empty!")
return None
list_tasks(tasks)
task = int(input(("Which task would you like to remove: ?")))
if task < 0 or task >= len(tasks):
print("Invalid input! Please select an appropriate task")
remove_task(tasks)
tasks.pop(task)
et enfin
Mettre à jour le fichier de tâche
def update_task_file(tasks):
file = open('tasks', 'w+')
for x in tasks:
file.write(x + '\n')
A quoi ça sert d'avoir des millions de fonctions quand je peux tout mettre comme je l'ai déjà fait? Maintenant quand tu dois jouer au jeu
tasks = read_task_file()
while True:
choice = read_task_choice()
if choice == Choices.list_task.value:
list_tasks(tasks)
elif choice == Choices.add_task.value:
add_new_task(tasks)
elif choice == Choices.remove_task.value:
remove_task(tasks)
else:
break
update_task_file(tasks)
C'est le principal avantage d'avoir des fonctions fortement typées.
Effacer l'écran et attendre la saisie
En raison de l'absence de graphiques, nous pouvons voir qu'après quelques choix, le terminal semble un peu étrange
Nous pouvons améliorer cela en effaçant simplement l'écran après chaque choix, puis en attendant que l'utilisateur appuie sur une touche
Effacer le terminal
Il y a plusieurs façons. Un moyen populaire consiste à utiliser os.system("cls")si vous êtes sous Windows, mais l'appeler est assez coûteux et rend également votre programme plus dépendant de la plate-forme.
Tu peux faire
print(chr(27) + "[2J")
Et cela fonctionnera également.
En attente d'entrée
L'ajout de cette ligne input("Press any key to continue...")attendra la réponse de l'utilisateur avant d'afficher à nouveau tous les choix, améliorant ainsi l'expérience.
Final
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
from enum import Enum
class Choices(Enum):
list_task = 1
add_task = 2
remove_task = 3
quit = 4
def read_int(prompt='> ', errmsg='Invalid number!'):
num = None
while num is None:
try:
num = int(input(prompt))
except ValueError:
print(errmsg)
return num
def display_menu():
print('What do you want to do?')
print('[1] List all tasks')
print('[2] Add a new task')
print('[3] Delete task')
print('[4] Quit')
def read_task_file():
file = None
if not os.path.exists('tasks'):
file = open('tasks', 'w+')
else:
file = open('tasks', 'r+')
tasks = []
for line in file.readlines():
tasks.append(line.strip())
return tasks
def update_task_file(tasks):
file = open('tasks', 'w+')
for x in tasks:
file.write(x + '\n')
def read_task_choice():
display_menu()
choice = read_int()
if choice not in Choices._value2member_map_:
print("Invalid input! Please enter a correct choice\n")
read_task_choice()
return choice
def add_new_task(tasks):
task = input("What task would you like to do: ")
tasks.append(task)
def list_tasks(tasks):
if len(tasks) == 0:
print("Task list is empty!")
return None
for i in range(len(tasks)):
print(f"{i} {tasks[i]}")
def remove_task(tasks):
if len(tasks) == 0:
print("Task list is already empty!")
return None
list_tasks(tasks)
task = int(input(("Which task would you like to remove: ?")))
if task < 0 or task >= len(tasks):
print("Invalid input! Please select an appropriate task")
remove_task(tasks)
tasks.pop(task)
def clear_screen():
print(chr(27) + "[2J")
def pause():
input("Press any key to continue...")
tasks = read_task_file()
while True:
clear_screen()
choice = read_task_choice()
if choice == Choices.list_task.value:
list_tasks(tasks)
elif choice == Choices.add_task.value:
add_new_task(tasks)
elif choice == Choices.remove_task.value:
remove_task(tasks)
else:
break
update_task_file(tasks)
pause()