如何从文件中在Python中生成元组列表

1 投票
5 回答
1890 浏览
提问于 2025-04-18 03:49

好的,我有一个文件,内容大概是这样的。

panite,1,1800
ruby,2,100
diamond,0.75,900
emerald,3,250
amethyst,2,50
opal,1,300
sapphire,0.5,750
benitoite,1,2000
malachite,1,60

我们的老师给了我们一段代码,里面用到了try/except来帮助我们打开文件。我需要打开这个文件,逐行读取内容,把每一行变成一个元组,然后放到一个列表里。这个列表的内容应该是最后一个数字除以中间的数字,然后把这个值和宝石的名字(中间的数字是宝石的克拉数)放在一起。现在我遇到的问题是,我连从文件里生成列表都做不到。我尝试过这样打开文件,但效果不太好。

def main():
    fileFound = False
    while not fileFound:
        fileName = input('File name containing jewel data: ')
        try:
            dataFile = open(fileName, "r")
            fileFound = True
            knapsack()
        except:
            print ('Could not find that file -- try again')

def knapsack():
    list = dataFile.readline()

其实我在把代码改成一个简单的打印语句时,有一点小成功,比如在def knapsack()下面打印2+2这样的简单内容。但是当我尝试创建列表时,却出现了异常错误。因为这是我第一门编程课,所以如果能得到一些建议,我会非常感激。

5 个回答

0

我会选择一种更符合Python风格的方法,使用列表推导式

def knapsack(dataFile):
    with open(dataFile, 'r') as fp:
        lines = [line.strip() for line in fp]

    data = [tuple(line.split(',')) for line in lines]

    return data

在这里,你是把文件的路径传递给你的背包函数。

0

如果我理解你的问题没错的话,出现这个错误是因为在 knapsack 函数里找不到 dataFile 这个变量。我建议你学习一下 Python 中的作用域规则,或者看看这一章,内容很简明扼要(或者在网上搜索一下这个话题也可以!)。

另外,我还建议你不要像你代码片段中那样处理所有的异常这是原因

修正后的代码可能看起来像这样:

def main():
    fileFound = False
    while not fileFound:
        fileName = raw_input('File name containing jewel data: ')
        try:
            dataFile = open(fileName, "r")
            fileFound = True
            knapsack(dataFile)
        except IOError:
            print ('Could not find that file -- try again')

def knapsack(dataFile):
    list = dataFile.readline() ### Or you want `readlines()` ?
    print list ### Print to let you know that it works
    # return list ### ???

if __name__ == '__main__':
    main()
0

使用 csv 模块可以把每一行当作csv的行来读取。

import csv

def knapsack(datafile):
    output_data = []
    csv_reader = csv.reader(datafile, delimiter=',')
    for row in csv_reader:
        output_data.append(tuple(row))
    return output_data

这样你会得到 output_data,内容如下:

[('panite', '1', '1800'),
 ('ruby', '2', '100'),
 ('diamond', '0.75', '900'),
 ('emerald', '3', '250'),
 ('amethyst', '2', '50'),
 ('opal', '1', '300'),
 ('sapphire', '0.5', '750'),
 ('benitoite', '1', '2000'),
 ('malachite', '1', '60')]

这其实是一个元组的列表。这样就解决了你从文件中生成列表的问题。接下来,你需要做的是:

  • 元组里的数字是字符串类型。在进行你提到的数学运算之前,确保 把它们转换成 int 类型。
  • output_data 作为参数传给一个单独的函数,这个函数会执行你在问题中提到的数学运算。这个函数应该负责生成你的输出列表。

关于你的代码,有几点需要注意:

  • 你在主函数中定义了文件句柄,但没有把它传给 knapsack 函数。而你在 knapsack 函数中引用了它,这样是无法得到你想要的结果的。所以你需要把 datafile 文件句柄作为参数传给 knapsack 函数。你可以通过把主方法中的这一行:

    knapsack()
    

    替换为:

    knapsack(datafile)
    
  • list 是Python内置类型的名称,所以最好不要用它作为变量名。

0

你应该:

  • dataFile 传给你的 knapsack 函数。
  • except 改成 except IOError,这样可以避免捕捉到你其实想看到的错误。
  • 关闭文件(可以考虑用 with 来打开文件,这样就不用手动关闭了)

    try:
        dataFile = open(fileName, "r")
        fileFound = True
        knapsack(dataFile)
        dataFile.close()
    except IOError:
        print ('Could not find that file -- try again')
    

如果你一开始就用了 except IOError,你会看到这个错误:

Traceback (most recent call last):
  ...
  ...
NameError: global name 'dataFile' is not defined

knapsack 不知道 dataFile 是什么,所以才会出错。总是 在使用 try..except 时捕捉 具体的 错误。如果你不知道会抛出什么错误,可以先在 Python 解释器里复现一下(比如试着打开一个不存在的文件,看看会抛出 IOError)。

knapsack 中,你需要把 readline 改成 readlines

def knapsack(dataFile):
    list = dataFile.readlines()

你还可以考虑使用 csv 模块,正如其他回答中提到的,用来处理数据。

1
def make_jewel(line):
    name, carats, price = line.split(",")
    return (float(price)/float(carats), name)

def main():
    while True:
        file_name = input('File name containing jewel data: ')
        try:
            with open(file_name) as inf:
                data = [make_jewel(line) for line in inf]
            break
        except FileNotFoundError:
            print('Could not find that file -- try again')

main()

还有一些评论:

  • except: 这个没有指定异常类型的写法,也叫“裸异常”,是不太推荐的,因为它会捕捉到 所有 的错误。你应该明确你希望捕捉的异常类型,只处理那些;如果你捕捉了所有错误,遇到一些完全意想不到的错误(比如 ComputerOnFireError!)你就永远不会知道发生了什么。

  • 使用 with 来打开文件是更好的选择,因为这样可以确保文件总是能被正确关闭。

  • 当你以文本模式打开文件时,可以逐行读取,这也是处理文件最常见的方式。

  • 当你对一个字符串使用 .split() 方法时,会得到一个字符串列表。在对这些部分进行数学运算之前,你需要用 int()float() 把它们从字符串转换成数字。

希望这些对你有帮助。

撰写回答