Программа управления задачами на Python
Я сделал простую программу на Python
- хранит задачи в файле
- позволяет пользователю управлять ими.
Мне интересно, эффективна ли моя реализация, и могу ли я сделать что-то лучше. Я не уверен, что загрузка всех данных из файла в память и их повторное сохранение в файле - хороший способ реализовать задачи сохранения списка.
#!/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')
Ответы
Начнем с самого верха.
CHOICE_LIST_TASKS = 1
CHOICE_ADD_TASK = 2
CHOICE_REMOVE_TASK = 3
CHOICE_QUIT = 4
Мне ясно, что вы хотите создавать переменные и присваивать им определенные целые числа, чтобы вам не приходилось нигде использовать магические числа, спасибо вам за это. Есть гораздо лучший способ реализовать эту идею на Python
Перечисления: Enum
Перечисления в Python
Перечисление - это набор символических имен
(членов), привязанных к уникальным постоянным значениям.
создание Enum
class Choices(Enum):
list_task = 1
add_task = 2
remove_task = 3
quit = 4
Это уже выглядит намного яснее, чем случайные глобальные переменные. Вы также можете перебирать перечисление и отображать его значения с именами .
print(Choices.add_task.name)
add_task
print(Choices.add_task.value)
1
Используйте больше функций
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())
Почему мы не можем переместить это в вызываемую функцию read_task_file()?
Таким образом, мне, вам, вам, после года чтения старых проектов и всем, кто когда-либо прочитает этот код, совершенно ясно, что эти несколько строк кода будут читать файл задачи . Без этого нужно внимательно прочитать код и понять его назначение.
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
теперь получение задач
tasks = read_task_file()
То же самое относится и к следующему набору кода, который позволит пользователю ввести свой выбор, чтобы мы могли его выполнить.
Выделение той части, где мы читаем выбор пользователя и выполняем функцию, будет выглядеть так:
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()
Примечание: Choices._value2member_map_будут все значения в перечислении.
Это уже выглядит намного чище! Мы устраняем необходимость иметь его в цикле, где он будет проверять все случаи, функция возвращает только choiceпри наличии действительного ввода.
Как я уже сказал, разделите работу на функции и все их, когда это необходимо. Я проделал то же самое с 4 основными работами (4 варианта).
Список задач
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 add_new_task(tasks):
return input("What task would you like to finish ?: ")
tasks.append(task)
Удалить задачу
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 update_task_file(tasks):
file = open('tasks', 'w+')
for x in tasks:
file.write(x + '\n')
Какой смысл иметь миллионы функций, когда я могу поставить все, как я уже сделал? Теперь, когда вам нужно играть в игру
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)
Это главное преимущество строго типизированных функций.
Очистка экрана и ожидание ввода
Из-за отсутствия графики мы видим, что после нескольких вариантов терминал выглядит немного странно.
Мы можем улучшить это, просто очищая экран после каждого выбора, а затем подождав, пока пользователь нажмет клавишу.
Очистка терминала
Есть несколько способов. Популярным способом является использование, os.system("cls")если вы работаете в Windows, но вызов этого довольно дорогостоящий, а также делает вашу программу более зависимой от платформы.
Ты можешь сделать
print(chr(27) + "[2J")
И это тоже сработает.
Ожидание ввода
Добавление этой строки input("Press any key to continue...")будет ждать ответа пользователя, прежде чем снова отобразить все варианты, что улучшит работу.
Финал
#!/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()