【问题标题】:Python newb: What's preventing this function from printing?Python newb:是什么阻止了此功能的打印?
【发布时间】:2014-08-09 01:16:08
【问题描述】:

背景

我对 python 的工作并不多,但我想用它来为我生成一些重复的 XML。现在,我只想解析 CSV,然后将这些值传递到 XML 节中。

有一个问题:我需要在编写 XML 之前重写一些 CSV。我有一些if 语句来为我处理这个问题,我决定通过将其移至单独的函数来减少混乱。

这就是我的问题出现的地方。我的writeTypes 函数似乎按预期工作但是当我返回重新编写的 csvDict 实例时,我无法再打印值。

显然我遗漏了一些东西,可能很简单——但是什么?下面是带有 cmets 的脚本。

脚本

import csv

def parseCSV(vals):

    # read the csv

    dictReader = csv.DictReader(open(vals, 'rb'), fieldnames=['name', 'type', 'nullable', 'default', 'description', '#'], delimiter=',', quotechar='"')

    # some repetitive xml; I will finish this portion later...

    stanza = '''
    <var name="{0}" precision="1" scale="None" type="{1}">
        <label>{2}</label>
        <definition><![CDATA[@{3}({4})]]></definition>
    </var>'''

    # a function that simply writes new values to dictionary entries 

    writeTypes(dictReader)

    # I'm confused here - nothing is printed to the console. 
    # If i comment my 'writeTypes function, prints as expected

    for i in dictReader:
        print i
        print i['type']


# function to rewrite 'types' key in dictionary set
def writeTypes(d):

    for i in d:
        if i['type'] == 'text':
            i['type'] = 't'
        elif i['type'] == 'boolean':
            i['type'] = 'l'
        elif i['type'] == 'double precision':
            i['type'] = 'd'
        elif i['type'] == 'integer':
            i['type'] = 'i'
        else:
            i['type'] = i['type']

         # unsurprisingly, this function does seem to print the correct values    
        print i

    # it seems as though there's something wrong with this return statement...
    return d

CSV 示例

(从 .gov 网站提取的公共数据)

Name,Type,Nullable,Default,Description,#
control,text,true,,,1,false
flagship,boolean,true,,,1,false
groupid,text,true,,,1,false
hbcu,text,true,,,1,false
hsi,text,true,,,1,false
iclevel,text,true,,,1,false
landgrnt,text,true,,,1,false
matched_n_00_10_11,boolean,true,,,1,false
matched_n_05_10_6,boolean,true,,,1,false
matched_n_87_10_24,boolean,true,,,1,false
name,text,true,,,1,false
name_short,text,true,,,1,false
school,text,true,,,1,false
sector,text,true,,,1,false
sector_revised,text,true,,,1,false
top_50,boolean,true,,,1,false
virginia,boolean,true,,,1,false

【问题讨论】:

标签: python xml csv


【解决方案1】:

dictReader 是一个迭代器,一旦通过 CSV 文件读取,它就会耗尽:进一步的迭代将不会做任何事情。

解决此问题的方法是在 writeTypes 中创建一个新的字典列表,以便您在此处而不是在原始值中分配值。然后,您可以返回该列表,并在 main 函数中对其进行迭代。

【讨论】:

  • 更明确一点,@Daniel Roseman 建议您在第一遍缓存文件的内容,并将其用于第二遍。虽然这很好用,但对于大文件来说,它非常占用内存。重写整个事情以一次性处理每一行对我来说似乎是最佳解决方案。
【解决方案2】:

@Jefftopia,问题是您第一次使用 dictReader 作为迭代器“消耗”了整个文件,因此当您尝试第二次迭代时没有任何内容可读取。

当你这样做时......

# a function that simply writes new values to dictionary entries 

writeTypes(dictReader)

... writeTypes 函数通过dictReader 遍历CSV 文件的行:

def writeTypes(d):
    for i in d:
        ...

然后你从那个函数返回并尝试遍历dictReader再次。问题是dictReader 现在没有数据可以从底层文件中读取,因为它已经完成了整个过程!

# I'm confused here - nothing is printed to the console. 
# If i comment my 'writeTypes function, prints as expected

for i in dictReader:
    print i
    print i['type']

当您在 Python 中使用 file 对象或最相似的对象作为迭代器时,迭代器会“使用”文件。作为一般规则,没有办法可靠地读取类似文件的对象,然后再回到开头再次读取它(考虑可能只传输一次数据的网络套接字的情况)。

在这种特殊情况下,您可以在第二次通过数据之前再次重新打开文件。 (还有更多杂乱无章的解决方案,但我不会展示它们。)

# reopen the file in order to read through it a second time
dictReader = csv.DictReader(open(vals, 'rb'), fieldnames=['name', 'type', 'nullable', 'default', 'description', '#'], delimiter=',', quotechar='"')
for i in dictReader:
    print i
    print i['type']

多次文件处理有时可以大大简化这样的代码,尽管它也会损害大文件的性能。在这种特殊情况下,一次完成所有事情会很简单。您可以简单地稍微重写代码,以便在遍历行时收集type 字段。

【讨论】:

  • 重新打开文件不会修复它,除非更改已保存到文件中,并且当前它们没有被保存。
  • @Rob Watts,这完全无关紧要。 OP 的代码没有对文件进行任何更改,只是读取它,因此在多遍方法中没有什么可以重新保存。
  • 我不确定你的意思,@Jefftopia。当您遍历 dictReader 时,它会为每一行提供一个 mutable dict 对象。您可以使用 for d in dictReader: d['type'] = rewriteTypeValue(d['type']) 之类的东西来读取每一行,然后在写出之前修改 type 字段或对其执行其他操作。
猜你喜欢
  • 1970-01-01
  • 2012-10-04
  • 1970-01-01
  • 1970-01-01
  • 2012-08-27
  • 2018-07-16
  • 1970-01-01
  • 2018-11-03
  • 1970-01-01
相关资源
最近更新 更多