Programa de gerenciamento de tarefas em Python
Eu fiz um programa simples em Python
- armazena tarefas no arquivo
- permite que o usuário os gerencie.
Estou interessado se minha implementação é eficiente e se poderia fazer algo melhor. Não tenho certeza se carregar todos os dados do arquivo para a memória e salvá-los novamente no arquivo é uma boa maneira de implementar tarefas de salvamento de lista.
#!/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')
Respostas
Vamos começar do início.
CHOICE_LIST_TASKS = 1
CHOICE_ADD_TASK = 2
CHOICE_REMOVE_TASK = 3
CHOICE_QUIT = 4
Está claro para mim que você deseja criar variáveis e atribuir a elas certos números inteiros para que não precise usar números mágicos em lugar nenhum, parabéns por isso. Há uma maneira muito melhor de implementar essa ideia em python
Enumerações: Enum
Enumerações em Python
Uma enumeração é um conjunto de nomes simbólicos
(membros) vinculados a valores constantes e únicos
criando um Enum
class Choices(Enum):
list_task = 1
add_task = 2
remove_task = 3
quit = 4
Isso já parece muito mais claro do que variáveis globais aleatórias. Você também pode iterar por meio da enumeração e exibir seus valores com nomes .
print(Choices.add_task.name)
add_task
print(Choices.add_task.value)
1
Use mais funções
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())
Por que não podemos mover isso para uma função chamada read_task_file()?
Desta forma, é extremamente claro para mim, você, você depois de um ano lendo projetos antigos, e qualquer outra pessoa que já tenha lido este código que essas poucas linhas de código vão ler o arquivo de tarefa . Sem isso, deve-se ler o código completamente e entender seu propósito.
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
agora conseguir as tarefas é
tasks = read_task_file()
O mesmo se aplica ao próximo conjunto de código, que permitirá ao usuário inserir sua escolha para que possamos executá-la.
Fatorar a parte em que lemos uma escolha do usuário e executamos em uma função pareceria
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()
Nota: Choices._value2member_map_serão todos os valores em uma enumeração.
Isso já parece muito mais limpo! Eliminamos a necessidade de tê-lo em um loop onde verificará todos os casos, a função só retorna choicequando existe uma entrada válida.
Como eu disse, divida o trabalho em funções e todas elas quando necessário. Fiz o mesmo para os 4 trabalhos principais (as 4 opções).
Listar tarefas
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]}")
Adicionar nova tarefa
def add_new_task(tasks):
return input("What task would you like to finish ?: ")
tasks.append(task)
Remover tarefa
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)
E finalmente
Atualizar arquivo de tarefa
def update_task_file(tasks):
file = open('tasks', 'w+')
for x in tasks:
file.write(x + '\n')
De que adianta ter milhões de funções quando posso colocar tudo como já fiz? Agora, quando você tem que jogar o jogo
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)
Esta é a principal vantagem de ter funções fortemente tipadas.
Limpar a tela e aguardar entrada
Devido à ausência de gráficos, podemos ver que após algumas escolhas o terminal parece um pouco estranho
Podemos melhorar isso simplesmente limpando a tela após cada escolha e, em seguida, esperar que o usuário pressione uma tecla
Limpando o terminal
Existem algumas maneiras. Uma maneira popular é usar os.system("cls")se você estiver no Windows, mas chamar isso é bastante caro e também torna o programa mais dependente da plataforma.
Você pode fazer
print(chr(27) + "[2J")
E isso também vai funcionar.
Esperando por entrada
Adicionar esta linha input("Press any key to continue...")irá esperar pela resposta do usuário antes de exibir todas as opções novamente, tornando a experiência melhor.
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()