如何从文件中在Python中生成元组列表
好的,我有一个文件,内容大概是这样的。
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 个回答
我会选择一种更符合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
在这里,你是把文件的路径传递给你的背包函数。
如果我理解你的问题没错的话,出现这个错误是因为在 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()
使用 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内置类型的名称,所以最好不要用它作为变量名。
你应该:
- 把
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
模块,正如其他回答中提到的,用来处理数据。
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()
把它们从字符串转换成数字。
希望这些对你有帮助。