【问题标题】:User-specified csv reading and printing in Python 3Python 3 中用户指定的 csv 读取和打印
【发布时间】:2013-08-17 20:43:37
【问题描述】:

我有一个脚本,它应该读取位于同一目录中的用户指定的 2 列 csv 文件,对数据进行一些数学运算,然后将结果打印到另一个用户定义的 csv 文件 stdout。我在 2.7.5 中制作了它,但现在终于移到了 3.2,它不起作用。我知道这并不令人震惊,但我在编程方面相当缺乏经验,而且我无法弄清楚如何让它在 Python 3 中工作。

我已将代码剥离为过去可以工作的基本阅读和打印元素,尽管做了一些更明显的修改,但它仍然无法在 3.2 中工作,它只是卡住了,从不打印到新文件.我曾尝试使用 2to3.py 但它会引发错误的输入解析错误并且没有进行任何更改!我宁愿确切地了解为什么它现在不管用了。

我想要的命令类型是;

somedirectory>myscript inputdata.csv > outputdata.csv

这是 Python 2.7.5 脚本的精简版,它可以运行,因此您可以看到我在做什么,(我已保留所有导入)

import fileinput, math, sys, numpy as np
from numpy import linspace, loadtxt, ones, convolve
from optparse import OptionParser

def main():
    parser = OptionParser() 
    options,args = parser.parse_args()
    try:
        data = [(line.rstrip()).split(',') for line in fileinput.input(args)]
    except IOError as detail:
        print >> sys.stderr, detail
        sys.exit(2)

    '''kept these lines in just to make sure the data is in the same format as when it worked before'''
    t = [float(row[0]) for row in data]
    m = [float(row[1]) for row in data]
    result = [[a,b] for a,b in zip(t, m)]

    for line in result:
        print >> sys.stdout, str(line[0]) + ',' + str(line[1])

options = 0
if __name__ == "__main__":
    main()

显然 Print 现在是一个函数,不推荐使用的 Optparse 可以转换为 Argparse 等

所以我认为这样就可以了,

import fileinput, math, sys, inspect, numpy as np
from numpy import linspace, loadtxt, ones, convolve
from argparse import ArgumentParser

def main():
    parser = ArgumentParser()   
    options,args = parser.parse_args()
    try:
        data = [(line.rstrip()).split(',') for line in fileinput.input(args)]
    except IOError as detail:
        print(detail, file=sys.stderr)
        sys.exit(2)

    '''kept these lines in just to make sure the data is in the same format as when it worked before'''
    t = [float(row[0]) for row in data]
    m = [float(row[1]) for row in data]
    result = [[a,b] for a,b in zip(t, m)]

    for line in result:
        print(str(line[0]) + ',' + str(line[1]), file=sys.stdout)

options = 0
if __name__ == "__main__":
    main()

这可能存在一些明显的问题,但在研究了所有元素之后,我被困在它到底在哪里崩溃了。

此外,可能还有更好的方法来读取和写入这种类型的 csv 文件,我只是坚持这样做,因为我知道它确实 工作。例如,我知道 csv 模块,但我找不到任何从命令行在用户指定的文件上使用它的示例,比如我需要它,我能找到的所有示例都定义了要在脚本本身中打开的文件。

提前谢谢你。

【问题讨论】:

    标签: python csv python-3.x


    【解决方案1】:

    代码之前的一些事情。如果您使用argparse 模块,您必须指定它必须接收文件名作为输入。这就是我对add_argument 所做的。由于参数不是可选的,如果用户没有指定文件名,应用程序将退出。

    如果用户指定了文件名,我会尝试打开它并创建一个 csv 阅读器。 csv阅读器只是一个解析文件的迭代器,所以我可以遍历每一行,我这样做并填充结果列表。填充列表后,应用程序将遍历列表并打印出所有元素。 try/except 是否有任何问题。

    import io
    import csv
    import argparse
    
    def main():
        # Create the parser
        parser = argparse.ArgumentParser()
        parser.add_argument('filename', help='Name of the file you want to load')
        args = parser.parse_args()
    
        result = []
        with io.open(args.filename, 'r', encoding='utf-8') as f:
            reader = csv.reader(f)
            for row in reader:
                result.append([row[0], row[1]])
    
        for item in result:
            print('{0}, {1}'.format(*item))
    
    if __name__ == "__main__":
        try:
            main()
        except Exception as e:
            print('Something went wrong {0}'.format(e))
    

    【讨论】:

    • 谢谢,这看起来更像是应该怎么做的!但是我似乎无法让这段代码工作。如果我不使用 argparse 并将 io.open() 中的对象更改为特定的文件名,则运行良好,但是当我如上所述使用时,在命令行中使用命令时会出现“错误:参数很少”我在上面给出的格式。它应该可以工作,因为它与使用状态的格式相同。事实上,无论我如何尝试,它似乎都无法识别我调用的任何输入文件。为此,您应该如何在命令中调用输入文件?
    • 您无需更改任何内容,只需将其保存到 myscript.py 并按照您在问题中所述的方式调用它:python myscript.py inputdata.csv > outputdata.csv
    • 谢谢,玩了一会儿我也发现了。这不完全是我所说的命令。使用旧代码,我会将目录更改为我的脚本和 csv 的位置,CD C:\somedirectory,然后键入命令myscript inputdata.csv > outputdata.csv。现在我需要指定“python”和 python 脚本的扩展名,不完全是我想要的,但至少它现在可以工作了!
    • 你是linux还是windows?
    • 你能复制echo %PATHEXT%的输出吗
    【解决方案2】:

    这个main 有效,只是改变print:

    def main():
        parser = OptionParser()
        options,args = parser.parse_args()
        try:
            data = [(line.rstrip()).split(',') for line in fileinput.input(args)]
        except IOError as detail:
            print(detail, file=sys.stderr)
            sys.exit(2)
    
        '''kept these lines in just to make sure the data is in the same format as when it worked before'''
        t = [float(row[0]) for row in data]
        m = [float(row[1]) for row in data]
        result = [[a,b] for a,b in zip(t, m)]
    
        for line in result:
            print(', '.join(str(x) for x in line), file=sys.stdout)
    

    你没有从第二个版本得到任何东西的原因是sys.exit(2)的缩进

    except IOError as detail:
        print(detail, file=sys.stderr)
    sys.exit(2)
    

    它退出而不继续正常输出

    对 argparse 进行更正(允许 1 个或多个输入文件):

    def main():
        parser = ArgumentParser()
        parser.add_argument('infiles',nargs='+')
        args = parser.parse_args()
        try:
            data = [(line.rstrip()).split(',') for line in fileinput.input(args.infiles)]
        except IOError as detail:
            print(detail, file=sys.stderr)
            sys.exit(2)
    
        '''kept these lines in just to make sure the data is in the same format as when it worked before'''
        t = [float(row[0]) for row in data]
        m = [float(row[1]) for row in data]
        result = [[a,b] for a,b in zip(t, m)]
    
        for line in result:
            print(', '.join(str(x) for x in line))
    

    或者您可以让argparse 负责打开文件(并在需要时引发错误):

    import argparse
    def main():
        parser = argparse.ArgumentParser()
        parser.add_argument('infiles',nargs='+', type=argparse.FileType('r'))
        args = parser.parse_args()
        data = [row for file in args.infile for row in csv.reader(file)]
    
        '''kept these lines in just to make sure the data is in the same format as when it worked before'''
        t = [float(row[0]) for row in data]
        m = [float(row[1]) for row in data]
        result = [[a,b] for a,b in zip(t, m)]
    
        for line in result:
            print(', '.join(str(x) for x in line))
    

    FileType 还将'-' 识别为stdin(或者对于('w') 文件,stdout)

    【讨论】:

    • 抱歉,sys.exit(2) 这只是我的问题中的格式错误,在我运行的实际脚本中是正确的。感谢您的回答,尽管根据我对维克多的回复,这些似乎仍然不起作用,可能是我的结果出了问题!如果我使用 main() 的第一个版本,脚本只会挂起并且不会退出。如果我使用第二个,我会得到与 Victor 的答案相同的“错误:参数太少”(这里的问题必须与 argparse 有关)。第三个奇怪的是我得到“NameError: global name 'argparse' is not defined”!
    • global name 'argparse' is not defined 只是表示argparse 没有被导入。我切换到argparse.ArgumentParser,因为我也在使用argparse.FileType。
    • 有时我添加print sys.argv 以查看argparse 使用的字符串。通常应该是['scriptname.py','arg1','arg2',...]. argparse` 使用sys.argv[1:],除了第一个。 sys.argv[0] 用作默认的 prog 值(在使用消息中)。
    猜你喜欢
    • 1970-01-01
    • 2014-02-08
    • 1970-01-01
    • 1970-01-01
    • 2020-08-28
    • 2017-07-26
    • 2019-04-29
    • 1970-01-01
    • 2016-04-06
    相关资源
    最近更新 更多