Python의 작업 관리 프로그램

Oct 08 2020

파이썬으로 간단한 프로그램을 만들었습니다

  • 파일에 작업 저장
  • 사용자가 관리 할 수 ​​있습니다.

내 구현이 효율적이고 더 나은 것을 할 수 있는지 관심이 있습니다. 파일에서 메모리로 모든 데이터를로드하고 파일에 다시 저장하는 것이 목록 저장 작업을 구현하는 좋은 방법인지 확실하지 않습니다.

#!/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')

답변

3 AryanParekh Oct 08 2020 at 20:53

맨 위부터 시작합시다.

CHOICE_LIST_TASKS = 1
CHOICE_ADD_TASK = 2
CHOICE_REMOVE_TASK = 3
CHOICE_QUIT = 4

변수를 만들고 특정 정수를 할당하기를 원한다는 것은 분명합니다. 그래야 어디서나 매직 넘버를 사용할 필요가 없습니다. 이 아이디어를 파이썬으로 구현하는 훨씬 더 좋은 방법이 있습니다.

열거 : 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()없습니까?
이런 식으로 나, 당신, 오래된 프로젝트를 읽은 지 1 년이 지나면,이 코드를 읽을 사람은 그 몇 줄의 코드 가 작업 파일을 읽을 것이라는 사실이 매우 분명 합니다 . 그것 없이는 코드를 철저히 읽고 그 목적을 이해해야합니다.

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()