0

I'm writing a task list program Python. In my function delete_task, I've asked the user to input a string to give the indices of the tasks they'd like to delete. It will accept inputs like 1, 1, 2, 1-3, 1-2, 4, 5 and so on, and then produce the indices list, e.g. the input 1-3, 5 will produce the list [1, 2, 3, 5].

Of course, the problem with trying to delete items from a list this way is that the indices will change every time I remove an item. So I tried using a list comprehension to pick out the items in my task list which are not in my indices list.

def delete_task():
    display_list()
    indices = parse_range(input("\nEnter the task number[s] to delete: "))
    deltodo = [task for index, task in enumerate(todo, 1) if index not in indices]
    todo = deltodo

todo is a list of class objects. Here's the class declaration:

class Task():
    t = ""
    checked = False
    def __init__(self, t, checked):
        self.t = t
        self.checked = checked

global todo
todo = []

The problem occurs on the list comprehension, the program throws the error:

Traceback (most recent call last):
  File "todo.py", line 123, in <module>
    delete_task()
  File "todo.py", line 38, in delete_task
    deltodo = [task for index, task in enumerate(todo, 1) if index not in indices]
UnboundLocalError: local variable 'todo' referenced before assignment

According to this link, one solution to this problem is to make sure that the variable is global. I know that this is bad practice etc., but as the program is only for me I tried doing it. But it still returns the error above.

I'm not sure what I'm doing wrong, or how to avoid this error.

EDIT: In response to mkrieger1, I thought it was worth noting that I have used todo in other functions without declaring it global, and it hasn't caused any problems. For example, here's my add_task function.

def add_task():
    clear()
    display_list()
    t = Task(input("\nTask: "), False)
    todo.append(t)
    save_list()

If I need to declare todo globally in each function, why does it work here but not in delete_task?

Lou
  • 2,200
  • 2
  • 33
  • 66
  • Does this answer your question? [Don't understand why UnboundLocalError occurs (closure)](https://stackoverflow.com/questions/9264763/dont-understand-why-unboundlocalerror-occurs-closure) – mkrieger1 Aug 26 '20 at 09:24
  • 1
    `todo` already is a global variable in your case. If you want to assign to it inside `delete_task` you need to write `global todo` *inside `delete_task`*, as explained in the article you have linked. – mkrieger1 Aug 26 '20 at 09:26
  • @mkrieger1, Your explanation makes sense, but I'm wondering why I haven't encountered problems in any of my other functions. I've edited a further explanation. – Lou Aug 26 '20 at 09:30
  • You only need to use the `global` keyword if you want to *assign* to a global variable. – mkrieger1 Aug 26 '20 at 09:31
  • 1
    @Lou You can append or use global variables outside of their scope. You just can't modify them. – Safwan Samsudeen Aug 26 '20 at 09:31
  • See https://stackoverflow.com/questions/4693120/use-of-global-keyword-in-python. – mkrieger1 Aug 26 '20 at 09:31
  • Ah, thanks. I've added `global todo` at the beginning of the function and that's solved the problem. – Lou Aug 26 '20 at 09:34

1 Answers1

1

Put the global todo statement at the top of the delete_task function. The global keyword allows you to modify the variable outside of the current scope, so you must put that inside the scope you want to modify it in. In this case it's in delete_task.

def delete_task():
    global todo
    display_list()
    indices = parse_range(input("\nEnter the task number[s] to delete: "))
    deltodo = [task for index, task in enumerate(todo, 1) if index not in indices]
    todo = deltodo

EDIT: Replying to your question that why the error doesn't come in other functions, you can append or use global variables outside of their scope. You just can't modify them.

Check this link for more information about the global keyword

Safwan Samsudeen
  • 1,645
  • 1
  • 10
  • 25