1

main(), invoice.close(), 和它上面的 print 函数都抛出“无效语法”异常。

我对字典或函数一无所知(此时),所以这是我能想到的最好的。

这是我想要的结果:

在此处输入图像描述

以下是 的内容invoice.txt

#### CONTENTS OF invoice.txt ###
# hammer#9.95
# saw#20.15
# shovel#35.40

编辑 *** 这是添加括号的例外 在 此处输入图像描述

print('{0: <10}'.format('Item'), '{0: >17}'.format('Cost'), sep = '' )

def main():
    invoice = open("invoice.txt", "r")

    count = 0
    total = 0

    hammer = invoice.readline()

    while invoice != "":
        saw = invoice.readline()
        shovel = invoice.readline()

        hammer = hammer.rstrip("\n")
        saw = saw.rstrip("\n")
        shovel = shovel.rstrip("\n")

        hammer = hammer.split("#")
        saw = saw.split("#")
        shovel = shovel.split("#")

        print('{0: <10}'.format(hammer[0]), '{0: >17}'.format('$' + hammer[1]), sep = '' )
        print('{0: <10}'.format(saw[0]), '{0: >17}'.format('$' + saw[1]), sep = '' )
        print('{0: <10}'.format(shovel[0]), '{0: >17}'.format('$' + shovel[1]), sep = '' )

        # total = total + float(hammer[1]) + float(saw[1]) + float(shovel[1])         # DOESN"T WORK
        total = total + (int(float(hammer[1])) + int(float(saw[1])) + int(float(shovel[1]))

        # total = total + (int(hammer[1])) + (int(saw[1])) + (int(shovel[1]))         # DOESN"T WORK
        print("{0: <10}".format("Total cost") + "{0: >17}".format("{0:.2f}".format(float(total))))

    invoice.close()
main()

4

3 回答 3

0

假设内容实际上只是

hammer#9.95
saw#20.15
shovel#35.40

这只是一个使用 a作为分隔符的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
于 2019-11-24T06:20:42.743 回答
0

这里的许多格式化代码都是多余的,并且对文本文件中的名称进行硬编码是不可扩展的。如果您需要引入新项目,则必须更改所有代码。我们应该通过编写一个辅助函数来处理打印来保持DRY 。format可以接受多个参数,从而简化事情。

其他一切都是读取文件(使用上下文管理器with,因此您不必担心记住调用close)、匹配有效行、拆分、剥离和转换数据的问题。一旦所有内容都在列表中,我们就可以调用该列表上sumlen函数来生成所需的总数。

我已经对列大小进行了硬编码——这些确实应该是参数,我们应该遍历数据以预先计算列名。但这可能是矫枉过正。

如果您的数据实际上是 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
于 2019-11-24T06:22:50.243 回答
0

语法错误

让我们退后一步,看看你的代码为什么不起作用。这是我在运行您的代码时收到的错误消息:

  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()and ,但您从来没有放下一个右括号!所以错误似乎比 Python 说的要早,但从解析器的角度来看,目前实际上没有问题。直到解析器到达第 31 行,我们才遇到问题;解析器期待一个右括号,但它得到了一个函数,并在第 31 行的函数上引发了一个错误,而不是在缺少括号的前一行。float()hammersawshovelprintprint

这些类型的事情需要时间来适应,但随着时间的推移,你会学到技巧和窍门。

更好地使用变量

在您的 Python 程序中,您不应该假设文本文件的内容。目前,您假设只有 3 个项目,并且您的变量名称似乎反映了您假设这些项目将是什么。如果文本文件包含数千个项目会怎样?为文本文件中的每个项目创建一个新变量是不可行的。您应该使用通用名称,例如,tool而不是hammersawshovel,并在循环的单独迭代中从文本文件中处理每个项目,而不是一次全部。

示例解决方案

这是为您提供的示例解决方案。就像你说的那样,使用字典会很好,所以下面的解决方案实现了一个返回项目字典的函数,其中键是项目名称,值是项目成本。然后使用该get_invoice函数返回发票的格式化字符串,并打印出发票。

def main():
    try:
        products = read_products("invoice.txt")
    except IOError as e:
        print('An error occurred while opening the file:', e)
        return
    except ValueError as e:
        print('An error occurred while reading the contents of the file:', e)
        return
    invoice = get_invoice(products)
    print(invoice)

def get_invoice(products):
    footer_headings = ('Total cost', 'Number of tools')

    # Get the length of the longest product name, to aid formatting.
    l_pad = len(max(products, key=lambda k: len(k)))
    l_pad = max(l_pad, len(max(footer_headings, key=lambda h: len(h))))
    r_pad = 10

    total = sum(products.values())
    count = len(products)

    header = 'Item'.ljust(l_pad) + 'Cost'.rjust(r_pad)
    body = '\n'.join([f'{p[0]}'.ljust(l_pad) + (f'${p[1]:.2f}').rjust(r_pad) for p in products.items()])
    footer = f'{footer_headings[0]}'.ljust(l_pad) + f'${total:.2f}'.rjust(r_pad) + '\n' + f'{footer_headings[1]}'.ljust(l_pad) + f'{count}'.rjust(r_pad)

    return f'{header}\n{body}\n\n{footer}'

def read_products(file_path):
    products = {}

    with open(file_path, "r") as f:
        for line in f:
            # Split the data
            data_split = line.rstrip("\n").split("#")

            # Ensure the data is safe to unpack
            if len(data_split) != 2:
                raise ValueError(f'Expected two fields but got {len(data_split)}')

            # Add the data to a dictionary for later use
            name, cost = data_split
            cost = float(cost)
            products[name] = cost

    return products

if __name__ == "__main__":
    main()
于 2019-11-24T06:26:39.157 回答