对于执行列表理解后dict上的循环不起作用

时间:2012-01-09 13:24:24

标签: python file list

我正在编写一些应该解析CSV文件的python代码。计算特定行的平均值,然后根据CSV文件中一行的值向收件人发送电子邮件。我的代码如下,我现在删除了发送代码的电子邮件,并将其替换为print语句:

def main():
  #smtp_instance = smtplib.SMTP('localhost')
  ldap_file = open('ldaps.csv','rU')
  ldap_data=csv.DictReader(ldap_file) 
  scores = list(int(d['score']) for d in ldap_data)

  average_score = sum(scores) / len(scores)
  print average_score

  for rows in ldap_data:
    ldap = rows['ldap']
    fullname = rows['fullname']
    firstname = fullname.split(' ')[0]
    location = rows['location']
    score = rows['score']
    if int(score) < average_score:
      score_msg = 'below'
    else:
      score_msg = 'above'

    print 'Hi ' + firstname + '\n'\
          'You got a ' + score + '% on your Final Exam.'\
          'The average score was ' + average_score + '.'\
          'This means that you scored ' + score_msg + ' average.'

if __name__ == '__main__':
  main()

当我运行它时会打印average_score值。但是代码永远不会进入for..loop。似乎我不能在字典上调用列表理解然后迭代同一个字典。知道我做错了什么以及如何解决它?

4 个答案:

答案 0 :(得分:6)

csv模块返回的阅读器对象表现为生成器,它们只能迭代一次。如果您想要一个可以重复迭代的真实列表,则必须明确创建:

ldap_data = list(csv.DictReader(ldap_file))

答案 1 :(得分:1)

这一行

scores = list(int(d['score']) for d in ldap_data)

消耗ldap_data中的所有数据。 ldap_data是由文件ldap_file中的基础数据驱动的迭代器。当您遍历ldap_data时,将使用基础文件ldap_file

所以ldap_data在到达for-loop时为空。

for rows in ldap_data:

解决此问题的一种方法是使ldap_data成为一个列表:

ldap_data  = list(csv.DictReader(ldap_file))

另一种方法是告诉ldap_file再次从头开始阅读:

scores = list(int(d['score']) for d in ldap_data)
...
ldap_file.seek(0)  
...
for rows in ldap_data:

答案 2 :(得分:1)

那是因为ldap_data是一个只支持迭代器协议的读者对象。这意味着您只能迭代一次,这是您在创建scores列表时所做的。

你必须把它放在一个集合中,或者,如果文件太大,在循环之前再读一遍。

答案 3 :(得分:0)

ldap数据的类型是什么?

我感觉它是一个迭代器,而不是一个列表,所以如果你遍历它一次(例如在列表解析中),下次你尝试迭代它时会立即抛出“StopIteration”。

尝试在

后立即将其复制到列表中
ldap_data = csv.DictReader(ldap_file) 
ldap_data = list(ldap_data)