假设内容实际上只是
hammer#9.95
saw#20.15
shovel#35.40
这只是一个DSV,使用#
作为分隔符。幸运的是,大多数CSV
程序都支持多个定界符,包括python的定界符。
import csv
from io import StringIO
def print_report(items,fields):
print("\t".join(fields))
total_cost = sum(float(item["Cost"]) for item in items)
for item in items:
print(f"{item['Item']}\t${float(item['Cost']):.2f}")
print()
print(f"Total cost\t${total_cost:.2f}")
print(f"Number of tools\t{len(items)}")
fields = ["Item","Cost"]
# This StringIO is basically like opening a file
s = StringIO(u"hammer#9.95\nsaw#20.15\nshovel#35.40")
items = list(csv.DictReader(s,delimiter="#",fieldnames=fields))
print_report(items,fields)
Item Cost
hammer $9.95
saw $20.15
shovel $35.40
Total cost $65.50
Number of tools 3
,
这里的许多格式代码都是多余的,并且对文本文件中的名称进行硬编码是不可扩展的。如果需要引入新项目,则必须更改所有代码。我们应该通过编写一个辅助函数来处理打印,从而保持DRY的状态。 format
可以接受多个参数,从而简化了事情。
其他所有事情都与读取文件有关(使用上下文管理器with
,因此您不必担心记住调用close
),匹配有效行,拆分,剥离和转换数据。一旦所有内容都在列表中,我们就可以在该列表上调用sum
和len
函数以生成所需的总计。
我已经硬编码了列大小-那些确实应该是参数,我们应该遍历数据以预先计算列名。但这可能太过分了。
如果您的数据实际上是CSV,但其余代码几乎相同,请使用CSV库。
import re
def fmt(x,y):
if isinstance(y,float):
y = "$" + "{:1,.2f}".format(y).rjust(5)
return '{0:<18}{1:>10}'.format(x,y)
if __name__ == "__main__":
items = []
with open("invoice.txt","r") as f:
for line in f:
if re.search(r"#\d+\.\d+$",line):
items.append([x.strip() for x in line.split("#") if x])
print(fmt("Name","Cost"))
for name,price in items:
print(fmt(name,float(price)))
print()
print(fmt("Total cost",sum([float(x[1]) for x in items])))
print(fmt("Number of tools",len(items)))
输出:
Name Cost
hammer $ 9.95
saw $20.15
shovel $35.40
Total cost $65.50
Number of tools 3
,
语法错误
让我们退后一步,看看为什么您的代码无法正常工作。
这是我运行您的代码时收到的错误消息:
File "test_2.py",line 31
print("{0: <10}".format("Total cost") + "{0: >17}".format("{0:.2f}".format(float(total))))
^
SyntaxError: invalid syntax
在Python中读取错误消息时,一开始会有很多信息可能会让人不知所措,但是一旦您学习了如何提取信息,它们将非常有帮助!让我们分解错误消息:
- 错误发生在
test_2.py
的第31行。在这种情况下,test_2
是我称为文件的文件,您的文件可能有所不同。
- 错误的类型是语法错误,这意味着Python无法正确解析代码行。
- 请注意
print statement
下的箭头:这准确指示了解析过程中引发错误的符号。
弹出的一个非常常见的语法错误是括号不匹配。使得该错误更加棘手的是,解析器将告诉您发现括号匹配问题的点,但是该问题可能位于完全不同的行上。这正是这里发生的情况,因此,我对syndax错误的一般规则是检查错误告诉您检查的行以及之前和之后的几行。
让我们仔细看看您指出的两行无效:
total = total + (int(float(hammer[1])) + int(float(saw[1])) + int(float(shovel[1]))
print("{0:<10}".format("Total cost") + "{0:>17}".format("{:.2f}".format(float(total))))
在第一行中,打开一个仿体(
,然后在int()
,float()
和{{1}上分别调用hammer
和saw
},但您永远不要放下右括号!因此错误似乎早于Python所说的,但是从解析器的角度来看,目前实际上没有问题。直到解析器到达第31行,我们才出现问题。解析器原本希望括号是闭合的,但是它却得到了shovel
函数,并在第31行的print
函数处而不是在前一行缺少括号的地方引发了错误。>
这些类型的东西需要时间来适应,但是随着时间的推移,您将学习技巧和窍门。
更好地使用变量
在Python程序中,您不应假定文本文件的内容。目前,您假设将只有3个项目,并且变量名似乎反映了您假设这些项目将是什么。如果文本文件包含数千个项目,会发生什么?为文本文件中的每个项目都创建一个新变量是不可行的。您应使用print
之类的通用名称,而不要使用tool
,hammer
和saw
,并在循环的单独迭代中而不是全部使用文本文件中的每个项。一次。
示例解决方案
这是为您提供的示例解决方案。如您所说,使用字典会很好,因此下面的解决方案实现了一个返回项字典的函数,其中键是项名称,值是项成本。然后使用shovel
函数返回发票的格式化字符串,并打印出发票。
get_invoice
本文链接:https://www.f2er.com/3042992.html