【问题标题】:How to properly handle errors while working with files?处理文件时如何正确处理错误?
【发布时间】:2020-11-24 16:42:11
【问题描述】:

节目说明:

程序从第一个输入中创建一个具有给定名称的.txt 文件。之后,它从每个输入中接受文件的文本行,直到输入仅包含字符串"end"(不应包括此结束行)。该程序还应该处理所有可能的错误。

我的解决方案:

def writef(f, st):
    try:
        assert st == "end", "* End of the file (not included)"
        assert not(f.endswith(".txt")), "txt only"
    except IOError:
        print("Unexpected error")
    except AssertionError as sterr:
        print(sterr)
    f.write(st + "\n")

t = input("* Beggining of the file (.txt supported only): ")
f = open(t, "w+")
while True:
    exec_st = input("> ")
    writef(f, exec_st)

问题:

  • 我的程序接受各种文件。我不知道如何处理一个错误,该错误将显示文件应该是.txt 扩展名(正确显示 AssertionError 消息)。
  • 如果字符串仅包含"end"* End of the file (not included),则在每个输入行之后它还会输出AssertionError 消息。但是,当我尝试输入仅包含单词 "end" 的字符串时,它会输出以下错误而不是 AssertionError:
Traceback (most recent call last):
 File "C:\Users\1\Desktop\IT\pycharm\em_1.py", line 15, in <module>
   writef(f, exec_st)
 File "C:\Users\1\Desktop\IT\pycharm\em_1.py", line 4, in writef
   assert not(f.endswith(".txt")), "txt only"
AttributeError: '_io.TextIOWrapper' object has no attribute 'endswith'

如果有任何帮助,我将不胜感激,在此先感谢。

【问题讨论】:

  • 您在问两个不同的问题。也就是说,您还没有包含您的 writef() 函数。
  • @ewong ,抱歉,确实错误地放置了我的解决方案的早期版本,进行了一些编辑

标签: python


【解决方案1】:

endswith 函数仅适用于字符串。如果要检查输入文件是否合法,可以通过检查f.name来实现。

在调用writef 之前不会检查文件扩展名,这没有意义,因为文件名已经在t = input("* Beggining of the file (.txt supported only): ") 中给出

t = input("* Beggining of the file (.txt supported only): ")
f = open(t, "w+")
assert f.name.endswith(".txt"), "txt only"

如果文件名不以“.txt”结尾,则上面的代码会引发AssertionError

try 块中的assert st == "end", "* End of the file (not included)" 会引发异常以输出AssertionError 每次用户键入“end”以外的任何内容。与其在 writef 中检查它,不如在 while 循环中进行。

while True:
    exec_st = input("> ")
    if exec_st == "end":
        f.close()
        break
    writef(f, exec_st)

上面的代码只要输入一个只包含“end”的字符串就中断循环,不会写入输出文件。

这里是完整的解决方案:

def writef(f, st):
    try:
        f.write(st + "\n")
    except IOError:
        print("Unexpected error")

t = input("* Beggining of the file (.txt supported only): ")
f = open(t, "w+")
assert f.name.endswith(".txt"), "txt only"
while True:
    exec_st = input("> ")
    if exec_st == "end":
        f.close()
        break
    writef(f, exec_st)

【讨论】:

  • 其实循环前断言错误的显示是怎么工作的呢?所以它会处理任何 IOError 消息并显示绑定到它的文本消息?
  • @JoshJohnson 如果文件名不以“.txt”结尾(即断言失败),断言语句将引发断言错误。由于它没有像以前那样被 try-except 块包围,因此错误将显示在控制台中。
【解决方案2】:

断言语句的工作方式是当你说时

assert st == "end", "* End of the file (not included)"

你是说你假设st 等于end。如果由于某种原因这不是真的,请引发错误。使用!= 将使程序按照您的解释运行,但是,您甚至不应该在这里使用断言语句。断言语句仅用于完整性检查,它们在生产中被剥离。我的意思是大多数公司会以一种特殊的优化模式运行 Python,这种模式会跳过断言语句。有关更多信息,请参阅this question。而是引发这样的错误:

if st == "end":
    raise RuntimeError("* End of the file (not included)")

这将确保您的错误在应有的时候出现,但我们仍然需要处理 '_io.TextIOWrapper' object has no attribute 'endswith' 错误。您正在检查 f 是否不以“.txt”结尾。 fopen() 返回的任何内容,如果您查找文档以查看该函数返回的内容,您会发现它不返回字符串,但 endswith 函数只能对字符串进行操作,因此会出现错误.您可以做的是将t 传递给您的writef 函数并检查它是否以“txt”结尾,或者您可以按照PIG208 提到的那样做并检查f.name 是否以“.txt”结尾。


需要考虑的其他事项:

  • 您应该养成使用更具描述性的名称的习惯。当您稍后回到您的代码时,它会为您提供帮助。我不知道tst 代表什么,将来你也不知道它们代表什么。

  • 您应该尽可能避免打印出“意外错误”,以支持更具体的错误消息。如果你不告诉他们发生了什么,你只会惹恼他们,当你的用户抱怨这个非常笼统的错误消息时,你会惹恼自己。

  • 您的 try catch 块围绕着一些不做任何 IO 工作的断言语句,但无论如何您都会捕获 IO 错误。这是没有必要的。如果您收到 IO 错误,它将来自 f.writeopenf.close

【讨论】:

  • 谢谢,IOError 会处理 .txt 错误吗?因此,例如,如果用户放置一个 .csv 文件并在输入中输入一个字符串,它将返回 IOError 消息,这是正确的还是我在这里错过了?
  • 不,您必须自己检查。 if not f.name.endswith(".txt"): raise RuntimeError("txt only").
【解决方案3】:

为了检查文件名,我建议你使用正则表达式,我建议你阅读它,因为在你这样做之前它没有任何意义。

对于“结束”的情况,我相信你想要f.close() 而不是f.close

如果您不想使用正则表达式,您可以检查文件名字符串是否包含“.txt”,这将解决大多数情况。

【讨论】:

    猜你喜欢
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    • 2018-12-06
    • 2012-12-28
    • 2010-10-11
    • 1970-01-01
    • 1970-01-01
    • 2010-11-12
    相关资源
    最近更新 更多