当列表为空时,列表推导会抛出异常

时间:2012-11-30 22:59:56

标签: python list list-comprehension

我有一个函数可以过滤列表项目,如果它们的日期是过去的(小于当前日期)。

meetings = []
def clean_old():
    meetings = [meeting for meeting in meetings if time.mktime(meeting) >= time.localtime()]

当列表为空时,此代码崩溃。

为什么会崩溃?它说for meeting in meetings,如果会议是空的,那么一切都应该没问题。

如何修复它以及该事件的解释是什么?

1 个答案:

答案 0 :(得分:7)

我认为你看到了这个例外:

UnboundLocalError: local variable 'meetings' referenced before assignment

您在这里遇到的内容与列表推导实际上没有任何关系。发生此错误的原因是您最初在函数外部定义了meetings,但是您试图在函数内部为其分配一个新值。

当Python看到变量在函数内部被赋值时,它会将其视为一个新变量,特定于该函数。这可以防止函数访问函数外部具有相同名称的任何变量。

在内部,Python正在做这样的事情:

meetings_outside = []

def clean_old():
    meetings_inside = [meeting for meeting in meetings_inside if time.mktime(meeting) >= time.localtime()]

您可以理解为什么会失败:meetings_inside正在定义。当Python尝试查找meetings_inside的值以开始迭代其内容时,它会失败,因为尚未为其分配值。

如何处理这取决于您使用的是哪个版本的Python,并且定义了meetings的初始值。

在Python 3中,您只需将nonlocal meetings添加到函数顶部即可。这将告诉它您指的是名为meetings的现有变量,而不是创建另一个变量。

但是你可能正在使用Python 2,它没有nonlocal关键字。 具有global关键字,它执行相同的操作,但仅限于在模块的顶层定义meetings:在任何其他函数或类之外。< / p>

例如,如果您的文件中没有其他内容,这将在Python 2中起作用:

导入时间

meetings = []

def clean_old():
    global meetings
    meetings = [meeting for meeting in meetings if time.mktime(meeting) >= time.localtime()]

clean_old()
print meetings
[]

但是这不会,因为meetings是在函数内部定义的:

import time

def main():
    meetings = []

    def clean_old():
        global meetings
        meetings = [meeting for meeting in meetings if time.mktime(meeting) >= time.localtime()]

    clean_old()
    print meetings

main()
NameError: global name 'meetings' is not defined

您需要解决此问题。最简单的方法是将赋值修改为:

 meetings[:] = [meeting for meeting in meetings if time.mktime(meeting) >= time.localtime()]

这告诉Python您要替换meetings内的所有值,但不会创建新的list对象。 (:语法称为“切片”,部分描述为in the Python tutorial。)