直接将生成器分配给字典会抛出StopIteration

时间:2014-03-27 18:36:02

标签: python generator

为什么此代码会抛出" StopIteration":

stub_generator = (x for x in range(5))
stub_dict = {}
stub_dict[next(stub_generator)] = list(stub_generator)

这有用吗?

stub_generator = (x for x in range(5))
stub_dict = {}
temp_1 = next(stub_generator)
temp_2 = list(stub_generator)
stub_dict[temp_1] = temp_2

2 个答案:

答案 0 :(得分:3)

这种行为是因为两件事:

  1. 赋值语句的右侧在左侧之前进行评估。

  2. 生成器对象只能迭代一次。


  3. 进一步解释,执行此代码时:

    stub_dict[next(stub_generator)] = list(stub_generator)
    

    这一部分:

    list(stub_generator) 
    

    将在此部分之前进行评估:

    stub_dict[next(stub_generator)]
    

    此外,将stub_generator置于list将导致生成器完全迭代并因此耗尽。之后评估next(stub_generator)时会引发StopIteration异常,因为stub_generator现在为空。


    但这段代码不同:

    temp_1 = next(stub_generator)
    temp_2 = list(stub_generator)
    

    执行next(stub_generator)之前执行list(stub_generator) 。这意味着,stub_generator在转换为列表时仍会包含一些项目。

答案 1 :(得分:1)

根据language reference for assignment statements

assignment_stmt ::=  (target_list "=")+ (expression_list | yield_expression)
  

赋值语句计算表达式列表(请记住,这可以是单个表达式或以逗号分隔的列表,后者产生元组)并将单个结果对象从左到右分配给每个目标列表。

因此,首先评估右侧的表达式。因此,首先执行list(stub_generator)并耗尽生成器,然后您正在执行next(stub_generator),它会尝试迭代已经耗尽的生成器。这就是StopIteration被提出的原因。