将元素插入到词典列表中

时间:2018-01-31 21:16:31

标签: python django

我已经声明了一个空列表,并且我想通过for循环使用extend()方法添加词典,但我最终得到的列表在其所有位置都具有相同的内容(相同字典)

这是代码:

def get_tasks(self, actor, task_state):
    tasks = Task.objects.filter(actor=actor.id, state=task_state)
    tasks_to_return = []
    task_data = {}

    for task in tasks:
        task_data['name'] = getattr(task, 'name')
        task_data['description'] = getattr(task, 'description')
        task_data['start_date'] = getattr(task, 'start_date')
        task_data['finish_date'] = getattr(task, 'finish_date')
        task_data['situation'] = task.get_situation()
        tasks_to_return.extend(task_data)

    return tasks_to_return

如果我为extend()更改了append(),结果就更糟了。

2 个答案:

答案 0 :(得分:3)

这是因为您每次都将相同的字典添加到列表中:实际上您只更改该字典的键/值,并再次添加该字典等等。

此外,通过使用extend,您实际上将可迭代的元素添加到列表中。字典是 iterable :您遍历密钥。

所以你应该做的是(1)每次构建一个新的字典,(2)使用append代替extend:

for task in tasks:
    task_data = {}
    task_data['name'] = getattr(task, 'name')
    task_data['description'] = getattr(task, 'description')
    task_data['start_date'] = getattr(task, 'start_date')
    task_data['finish_date'] = getattr(task, 'finish_date')
    task_data['situation'] = task.get_situation()
    tasks_to_return.append(task_data)

我们也可以改进代码,例如,不是设置键值对,我们可以在构造字典时这样做。您使用getattr(..),但这不是必需的:我们可以使用task.name代替getattr(task, 'name'),因此可能采用更优雅的方法:

tasks_to_return = []
task_data = {}
for task in tasks:
    task_data = {
        'name': task.name,
        'description': task.description,
        'start_date': task.start_date,
        'finish_date': task.finish_date,
        'situation': task.situation
    }
    tasks_to_return.append(task_data)

既然列表最初是空的,我们也可以使用 list comprehension

tasks_to_return = [ {
        'name': task.name,
        'description': task.description,
        'start_date': task.start_date,
        'finish_date': task.finish_date,
        'situation': task.situation
    } for task in tasks]

答案 1 :(得分:1)

您的extendappend会将原始引用添加到task_data,其内容会不断变化。相反,要么为task_data创建一个新的空对象,要么附加您重复使用的副本的副本:

import copy
...
    tasks_to_return.append(copy.copy(task_data))