简体   繁体   中英

Changing a list outside of the scope

I'm trying to remove an item from a list , like so:

TodoList=[{'ID':5,'TodoItem':'walk','isDone':False}];

def RemoveItem(ID):
     if not any(todoItem['ID'] == ID for todoItem in TodoList):
          return 'item does not exist';

     RemovedList=list(filter(lambda todoItem:todoItem['ID']!= ID,TodoList))
     TodoList=RemovedList

does not work, I also tried this:

 def RemoveItem(ID):
         nonlocal TodoList
         if not any(todoItem['ID'] == ID for todoItem in TodoList):
              return 'item does not exist';

         TodoList=list(filter(lambda todoItem:todoItem['ID']!= ID,TodoList))

does anyone know whats the problem?

One possible fix.

Passing the todo list (list of dict) as parameter, so it mutates:

TodoList=[{'ID':5,'TodoItem':'walk','isDone':False}, {'ID':6,'TodoItem':'talk','isDone':True}]

def RemoveItem(ID, TodoList):
     if not any(todoItem['ID'] == ID for todoItem in TodoList):
          print('item does not exist');
     else:
      for item in TodoList:
        if item['ID']== ID: TodoList.remove(item)


RemoveItem(5, TodoList)

print(TodoList)
#=> [{'ID': 6, 'TodoItem': 'talk', 'isDone': True}]


For your solution to work you need to return:

 def RemoveItem(ID, TodoList): if not any(todoItem['ID'] == ID for todoItem in TodoList): return 'item does not exist'; else: return list(filter(lambda todoItem:todoItem['ID']!= ID, TodoList)) print(RemoveItem(5, TodoList)) #=> [{'ID': 6, 'TodoItem': 'talk', 'isDone': True}] 

This is because the line list(filter(lambda todoItem:todoItem['ID']!= ID, TodoList)) doesn't mutate the list, it extracts elements based on condition.

But it is better to return the list itself if there is no item to delete, instead of returning a string.

A possible solution is to find the index of the item with id and use pop :

todo_list = [{'ID': 5, 'TodoItem': 'walk', 'isDone': False}]


def remove_item(ID):
    if not any(todoItem['ID'] == ID for todoItem in todo_list):
        return 'item does not exist'

    # get index of id
    idx = next(i for i, e in enumerate(todo_list) if e['ID'] == ID)

    # remove and return
    return todo_list.pop(idx)


print(remove_item(4))
print(remove_item(5))
print(todo_list)

Output

item does not exist
{'isDone': False, 'ID': 5, 'TodoItem': 'walk'}
[]

The problem with your first attempt is that when you do: TodoList=RemovedList inside of a function, it creates a new local variable inside the function, even if there is a global variable with the same name. In your second attempt, you need to set to global instead of nonlocal:

todo_list = [{'ID': 5, 'TodoItem': 'walk', 'isDone': False}]

def RemoveItem(ID):
    global todo_list
    if not any(todoItem['ID'] == ID for todoItem in todo_list):
        return 'item does not exist';

    todo_list = list(filter(lambda todoItem: todoItem['ID'] != ID, todo_list))


RemoveItem(5)
print(todo_list)

Output

[]

Further

  1. Documentation on global

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM