Program do zarządzania zadaniami w Pythonie
Zrobiłem prosty program w Pythonie
- przechowuje zadania w pliku
- umożliwia użytkownikowi zarządzanie nimi.
Interesuje mnie, czy moje wdrożenie jest wydajne i czy mógłbym zrobić coś lepszego. Nie jestem pewien, czy załadowanie wszystkich danych z pliku do pamięci i ponowne zapisanie ich w pliku to dobry sposób na zaimplementowanie zadań zapisywania listy.
#!/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')
Odpowiedzi
Zacznijmy od samej góry.
CHOICE_LIST_TASKS = 1
CHOICE_ADD_TASK = 2
CHOICE_REMOVE_TASK = 3
CHOICE_QUIT = 4
Jest dla mnie jasne, że chcesz tworzyć zmienne i przypisywać im określone liczby całkowite, więc nie musisz nigdzie używać magicznych liczb, chwała ci za to. Istnieje znacznie lepszy sposób na wdrożenie tego pomysłu w Pythonie
Wyliczenia: Enum
Wyliczenia w Pythonie
Wyliczenie to zbiór nazw symbolicznych
(członków) powiązanych z unikalnymi, stałymi wartościami
tworzenie pliku Enum
class Choices(Enum):
list_task = 1
add_task = 2
remove_task = 3
quit = 4
Już teraz wygląda to znacznie lepiej niż losowe zmienne globalne. Możesz również iterować wyliczenie i wyświetlać jego wartości z nazwami .
print(Choices.add_task.name)
Dodaj zadanie
print(Choices.add_task.value)
1
Użyj więcej funkcji
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())
Dlaczego nie możemy tego przenieść do funkcji o nazwie read_task_file()?
W ten sposób jest dla mnie niezwykle jasne, Ty, Ty po roku czytania starych projektów i każdego, kto kiedykolwiek przeczyta ten kod, że te kilka wierszy kodu przeczyta plik zadania . Bez tego trzeba dokładnie przeczytać kod i zrozumieć jego cel.
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
teraz otrzymuję zadania
tasks = read_task_file()
Dokładnie to samo dotyczy kolejnego zestawu kodów, który pozwoli użytkownikowi wprowadzić swój wybór, abyśmy mogli go wykonać.
Rozliczenie części, w której odczytujemy wybór od użytkownika i wykonujemy funkcję, wyglądałoby tak
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()
Uwaga: Choices._value2member_map_będą to wszystkie wartości w wyliczeniu.
To już wygląda na znacznie czystsze! Eliminujemy potrzebę posiadania go w pętli, w której sprawdzi wszystkie przypadki, funkcja zwraca tylko choicewtedy, gdy jest prawidłowe wejście.
Jak powiedziałem, rozłóż pracę na funkcje i wszystkie, gdy jest to wymagane. Zrobiłem to samo dla 4 głównych zadań (4 możliwości).
Lista zadań
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]}")
Dodaj nowe zadanie
def add_new_task(tasks):
return input("What task would you like to finish ?: ")
tasks.append(task)
Usuń zadanie
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)
I w końcu
Zaktualizuj plik zadania
def update_task_file(tasks):
file = open('tasks', 'w+')
for x in tasks:
file.write(x + '\n')
Jaki jest sens posiadania milionów funkcji, skoro mogę umieścić wszystko, co już zrobiłem? Teraz, kiedy musisz zagrać w grę
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)
Jest to główna zaleta posiadania silnie wpisanych funkcji.
Czyszczę ekran i czekam na wejście
Ze względu na brak Grafiki widzimy, że po kilku wyborach terminal wygląda trochę dziwnie
Możemy to poprawić, po prostu czyszcząc ekran po każdym wyborze, a następnie czekając, aż użytkownik naciśnie klawisz
Czyszczenie terminala
Sposobów jest kilka. Popularnym sposobem jest użycie w os.system("cls")systemie Windows, ale wywołanie tego jest dość drogie, a także sprawia, że program jest bardziej zależny od platformy.
Możesz to zrobić
print(chr(27) + "[2J")
I to też zadziała.
Czekam na wejście
Dodanie tej linii input("Press any key to continue...")spowoduje oczekiwanie na odpowiedź użytkownika przed ponownym wyświetleniem wszystkich wyborów, dzięki czemu wrażenia będą lepsze.
Finał
#!/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()