在Python中更改/写入CSV文件的单个值
我的代码出错了:
_csv.Error: sequence expected
我觉得这是因为我只想写一个值,而不是一个列表之类的东西。
exRtFile = open ('exchangeRate.csv')
exchReader = csv.reader(exRtFile)
exchWriter = csv.writer(exRtFile)
loop2=0
while loop2==0:
selected=int(input("Please select an option: "))
if selected == 1:
change = input("What rate would you like to change: ")
changeRt = float(input("What would you like to change the rate to: "))
for row in exchReader:
currency = row[0]
if currency == change:
crntRt = row[1]
crntRt = changeRt
exchWriter.writerow(crntRt)
exRtFile.close()
有什么好的方法来修复这个问题,或者有没有更好的方法来修改CSV文件中的一个值?
CSV文件:
Pound Sterling,1
Euro,1.22
US Dollar,1.67
Japanese Yen,169.948
2 个回答
回答你的问题:是的,问题在于你试图只写一个值,而 writerow
其实是需要一个列表。
那么……你考虑过稍微改变一下代码的工作方式吗?
这是我做的(我现在已经测试过了,所以我知道它能工作):
- 首先,询问用户要进行的所有更改,并将它们保存在一个
dict
中,字典的键是货币名称(比如 欧元),值是新的货币值(比如 5.0)。用户可以通过按0
退出循环。 - 其次,逐行打开并读取你的
exchangeRate.csv
文件。如果row[0]
(货币名称)在需要更改的值中,那么就在那一行进行更改。 - 无论发生什么情况(不管这一行是否需要更改),都将该行写入一个新的临时文件
exchangeRate.csv.tmp
中。 - 当原始文件的所有行都读取完后,你会得到
exchangeRate.csv.tmp
,其中有些行没有改变,有些行被改变了。将.tmp
文件替换为exchangeRate.csv
。
不知道……这可能改变得有点多?不过无论如何,给你看看:
import csv
import shutil
change_rates = {}
selected = 1
while selected:
selected=int(raw_input("Please select an option: (1 to change, 0 to exit)"))
if selected == 1:
change = raw_input("What rate would you like to change?: ")
changeRt = float(raw_input("What would you like to change the rate to: "))
change_rates[change] = changeRt
if len(change_rates) > 0:
with open('exchangeRate.csv', 'r') as f_in,\
open('exchangeRate.csv.tmp', 'w') as f_out:
exchReader = csv.reader(f_in)
exchWriter = csv.writer(f_out)
for row in exchReader:
if row[0] in change_rates:
row[1] = change_rates[row[0]]
exchWriter.writerow(row)
shutil.move('exchangeRate.csv.tmp', 'exchangeRate.csv')
下面是一个示例执行:
Please select an option: (1 to change, 0 to exit)1
What rate would you like to change?: Euro
What would you like to change the rate to: 5
Please select an option: (1 to change, 0 to exit)0
borrajax@borrajax:~/Documents/Tests$ cat ./exchangeRate.csv
Pound Sterling,1
Euro,5.0
US Dollar,1.67
Japanese Yen,169.948
你总是可以进行更多的优化,比如……允许不区分大小写的搜索,或者检查货币是否真的被改变(比如即使用户说想把 欧元 改为 5.0,如果那就是欧元的汇率,那就什么都不做)……类似这样的事情。
编辑 1:
我刚刚看到了 Larry Lustig 的 回答,我同意,对于像你这种小文件(可以完全加载到内存中的文件),我之前提到的持续从磁盘读取和写入并不是最优的。他的想法是将所有内容保存在内存中,然后一次性写入同一个 exchangeRate.csv
文件,可能更符合你的需求。
编辑 2:
为了回答你在这条回答下的评论中的问题:
exchangeRate.csv.tmp 末尾的 .tmp 是什么?
这只是一个新名称。我加上
.tmp
后缀是为了避免与原始文件(exchangeRate.csv)发生命名冲突。不过你可以随便命名(甚至可以叫foobar.baz
)。变量中的 'change' 在 change_rates[change] = changeRt 中有什么作用?
change
是一个变量,里面包含了要更改的货币名称(在我给出的示例中,change
包含字符串"Euro"
,因为那是用户(呃……我)在控制台输入的内容)。这只是访问 字典 的一种方式。在 row1=change_rates[row[0]] 中 '[row[0]]' 的目的是什么?
我们已经同意,在读取文件时,
row[0]
(就这样,不是[row[0]]
)包含了文件中货币的名称(欧元、英镑……等等),对吧?所以在执行的某个时刻,row[0]
将包含字符串"Euro"
,这(在我的测试示例中)是用户想要更改的货币。这个字符串("Euro"
)也是change_rates
字典中的一个键(因为用户说他想更改它),所以你在查询change_rates
字典中键为"Euro"
的项的值(这将给你5.0
)。这实际上就是在做change_rates["Euro"]
。为了更清楚一点,可以在if len(change_rates) > 0:
之前加上这一行print "要更改的货币: %s" % change_rates
(这将显示字典的样子)。shutil.move('exchangeRate.csv.tmp', 'exchangeRate.csv') 的作用是什么?
它将新货币的文件复制到
exchangeRate.csv
(见 shutil 文档)。
这里有一些代码,虽然没有测试过,但可以实现你想要的功能。这个思路是先把文本读到内存中,进行更新,然后把结果写回原来的文件。
你还可以进一步改进,比如问用户是否想保存他们的更改,或者让他们添加新的货币,而不是直接告诉用户这些货币是未知的。
在实际应用中,我会把这段代码分成三个独立的部分(或者甚至是类),一个负责读取,一个负责写入,还有一个负责编辑列表。
import csv
rates = {}
# read file into dictionary
with open('csv_file.csv', 'r') as in_file:
rdr = csv.reader(in_file)
for item in reader:
rates[row[0]] = row[1]
# ask user for updates and apply to dictionary
while true:
cmd = raw_input('Enter exchange rate to adjust, or blank to exit')
if cmd is None or cmd.strip() == '':
break
if rates.has_key(cmd):
new_rate = float(raw_input('Enter new exchange rate:'))
rates[cmd] = new_rate
else:
print 'Currency {} is not known.'.format(cmd)
# Write the updated dictionary back over the same file.
with open('csv_file.csv', 'w') as out_file:
wrtr = csv_writer(out_file)
wrtr.writerows(rates)