生成器缩小字典列表

时间:2015-09-24 15:42:15

标签: python python-3.x generator

我刚刚开始使用python进行编程,并且非常喜欢生成器的概念。

所以我有一个字典列表,每个字典都包含一个id和一个状态,例如前两个元素可能看起来像这样

 lst =[{ "id":1, "status": "new"}, {"id": 2, "status"="finished"}]

实际列表最多可包含10个项目。每个id对应一个作业,通常作业完成的顺序是随机的。

我想检查作业是否完成,如果是,请处理它。如果没有完成,(由于随机性)我想检查另一个工作,直到所有工作完成(通常他们将在某个时间)

所以对我而言,这对发电机来说是一个很好的用途,特别是在管道中(尽管效率在这里可能并不重要)。

def gener(lst):
    while lst:
    for item in lst:
        if item["status"] == "finished":
            yield lst.pop(list.index(item))  
        else:
            check_and_update_status(item)

检查和更新功能可能如下所示:

def check_and_update_status(item):
    item["status"]=finished

所以我的第一个问题是:这是一种有意义的方法吗?或者这是一个不好的选择。

所以,希望我能在这里添加这两个问题:

  1. 有时在列表中可能会出现没有状态键的词典。在这种情况下,我想在else分支中执行任务。我怎样才能做到这一点?异常处理?

  2. 在一些关于python /编程的文献中,我了解到设置和程序应该被划分。所以我想知道我是否应该硬编码“完成”(也许还有“状态”)。术语“完成”源于外部文件,可能在将来的某个时候更改。是否有一种优雅的方法来解决这个问题?

1 个答案:

答案 0 :(得分:1)

在迭代期间变异list是不安全的,通常不受支持。即使它有效,但只有lst.pop(lst.index(item))才能使用for i, item in enumerate(lst):这样做是愚蠢的,因此您可以免费获得索引。您可以采取的一种方法是避免在迭代时删除,只需将索引存储为delete,并使用list comprehension在最后重新生成lst。例如:

while lst:
    todel = set()
    for i, item in enumerate(lst):
        if item["status"] == "finished":
            todel.add(i)
            yield item  
        else:
            check_and_update_status(item)
    if todel:
        lst = [x for i, x in enumerate(lst) if i not in todel]

如果你有更大的列表和更频繁的从列表中删除,其他方法可能会更好地工作,但这种方法可以优化不频繁的删除,而无需在迭代副作用时注册危险的突变。

为了处理不存在的"status"键,您可以使用item.get("status")而不是索引语法来避免抛出异常(使用一个参数,get返回None如果key不存在,或者您可以传递第二个参数以用作默认值)。或者,要获取现有值(如果它存在),并设置并获取默认状态(如果它尚不存在),请使用item.setdefault("status", "new")(其中"new"应为您的默认起始状态)。

例如,要检查和设置,您可以使用:

if item.setdefault("status", "new") == "finished":

问题3在一般情况下难以回答;如果你有一个适当的数据模式,那么使用它而不是在魔术字符串中进行硬编码是一个好主意,但这取决于你的用例。