可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Ok I have a file like that looks like this.
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
Our teacher gave us code that uses a try/except to help us open the file. I need to open the file and read each line and make each line a tuple and then put it in a list. The list is supposed to be the last numbe divided by the middle number, and then that value followed by the name of the gem(the middle number is the carat of the gem). The problem i'm having is I cant even get it to make a list from the file. This is what i've tried to open it without much success.
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()
I've actually had a little success when I changed it to a simple printstatement under def knapsack() where it will print something simple like 2+2, but when I try to make a list, it gives me the except error instead. This is my first programming class so any insight into this would be appreciated.
回答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()
and some comments:
except:
without a specified exception-type, also known as a "bare exception", is frowned on because it catches everything. You should specify the type of exceptions you expect to see, and only handle those; if you catch everything and something totally unexpected fails (ie ComputerOnFireError
!) you will never find out about it.
opening a file using with
is preferred because it ensures the file will always get closed properly.
when you open a file in text mode, you can iterate over it line-by-line; this is the most common way to process a file.
when you .split()
a string, you get a list of strings back. Before doing math on the pieces you have to convert them from a string to a numeric value using int()
or float()
.
Hope that helps.
回答2:
Use the csv module to read lines as csv rows.
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
This will give you output_data
as:
[('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')]
which is a list of tuples. This solves your problem of making a list from the file. Now, you should do:
- The numerals in the tuples are strings. You need to make sure you convert them to
int
before you do the arithmetic operations as you mention in your description.
- Pass
output_data
as an argument to a separate function that does the arithmetic functions you mentioned in your question. This function should build your output list.
A few remarks on your code:
You define the file handle in the main function, but do not pass it
to the knapsack
function. But you reference it in the knapsack
function which will not give you what you want. So you need to pass
the datafile
file handle as argument to your knapsack
function. You do this by replacing this line in your main
method from:
knapsack()
to
knapsack(datafile)
list
is the name of a built in type in Python. So it is wise not to use it as the name of a variable in your code.
回答3:
You should:
- send
dataFile
to your knapsack
function.
- change from
except
to except IOError
to avoid catching exceptions you do want to see.
close the file (consider using with
to open the file to avoid having to close it explicitly
try:
dataFile = open(fileName, "r")
fileFound = True
knapsack(dataFile)
dataFile.close()
except IOError:
print ('Could not find that file -- try again')
If you had used except IOError
from the start of, you would have seen this error:
Traceback (most recent call last):
...
...
NameError: global name 'dataFile' is not defined
knapsack
does not know what dataFile
is, hence the error. Always catch specific exceptions when using try..except
. If you don't know which error is thrown - reproduce it before you write the code in the python interpreter (e.g try to open a file that doesn't exists, and notice that IOError
is thrown).
In knapsack
you need to change from readline
to readlines
.
def knapsack(dataFile):
list = dataFile.readlines()
You should also consider to use the csv
module as mentioned in the other answer to handle the data.
回答4:
If I understand your question correctly, the exception is because dataFile
variable is not found inside the knapsack
function. I'd suggest learning scoping rules in Python or read this excellent to-the-point chapter on the topic (or search for this topic on the Web!).
The other thing I'd recommend is not to handle all exceptions as you've shown in your snippet. Here's why.
The fixed code could look something like this:
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()
回答5:
I would go with something more Pythonic using list comprehensions
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
Where you are passing to your knapsack function the path to your file.