Python 2.7 中的文件打开操作行为异常

File opening operation misbehaving in Python 2.7

我正在学习异常,因此执行一些文件操作并测试在处理 Python 中的文件时可能产生异常的代码的各个部分。我正在 Canopy 上执行此 Python 2.7 代码。

#!/usr/bin/python

import os

try:
    fp = open('testfile', 'r')
except IOError:
    print 'File not opened successfully'
else:
    print 'File opened successfully'
    try:
        fp.write('Hello!')
    except IOError:
        print 'Write not allowed on this file'
    else:
        print 'Write successful'
        try:
            fp.close()
        except IOError:
            print 'File not closed properly'
        else:
            print 'File closed successfully'
finally:
    if os.path.exists(fp.name):
        os.remove(fp.name)

当我执行这段代码时,我得到以下输出:

File not opened properly

NameErrorTraceback (most recent call last)

/home/sr/Python/tcs.py in ()

--> 185 if os.path.exists(fp.name)

NameError: name 'fp' is not defined

但是,如果我将文件的访问模式更改为 'w',那么一切似乎都可以正常工作,正确的输出如下:

File opened successfully

Write successful

File closed successfully

我无法理解为什么 'r' 模式无法正确打开文件,因此无法创建 fp 文件对象。请帮我解决问题。

P.S.: 另外我想知道是否有更好的方法来实现同样的事情。但这是可选的。

说明

结合您的打印输出的错误应该是不言自明的:如果您无法打开文件,变量 fp 不存在。

模式'r'表示您要打开文件进行r阅读。您无法读取不存在的内容,因此在处理 IOError 之后,您最终会转到代码中的 finally 块。但是错误发生在 fp 被设置之前,所以没有变量 fp,因此错误。 [以下解决方案]

模式 'w' 表示您想要打开 writing,但要从头开始。如果文件已经存在,还有一个 'a' 模式可以 a 追加。您可以很好地写入一个不存在的文件,因此您的代码不会失败。事实上,如果文件确实以 'w' 模式存在,它将被截断并且之前的任何内容都将丢失。

尝试创建一个空文件并运行模式'r'。您应该得到一个打印 'Write not allowed on this file' 的异常。这是因为,正如您的错误消息正确指示的那样,不允许写入以读取模式打开的文件。

改进

您可以对代码进行两项主要改进。一个是修复逻辑缺陷,另一个是使用 with 语句对文体进行重大改进。

你有两个主要的逻辑错误。第一个位于您已经看到的最外面的 finally 块中。最简单的修复方法是将 finally 块的内容移动到 else 中,因为如果文件未打开,您无需执行任何操作。另一种解决方案是首先引用您尝试打开的文件名。例如,您可以将文件名存储到一个变量中并使用它:

filename = 'testfile'
try:
    fp = open(filename, 'r')
...
finally:
    if os.path.exists(filename):
        os.remove(filename)

第二个主要逻辑错误是写失败没有关闭文件。请注意,您仅在 try 块的 else 子句中调用 fp.close()。相反,如果应该出现在 finally 块中。 print语句当然应该留在else中。变化

 else:
    print 'Write successful'
    try:
        fp.close()
    ...

 else:
    print 'Write successful'
 finally:
    try:
        fp.close()
    ...

可以通过使用 with 块来管理文件操作来改进整个代码的风格。执行此操作的明显方法如下:

fname = 'testfile'
with open(fname, 'r') as fp:
    fp.write('Hello!')
if os.path.exists(fname):
    os.remove(fname)

当事情失败时,您不会收到那么多的详细消息,但总的来说,这段代码比您现有的代码更简洁、更短且更健壮。它保证无论过程中任何地方是否发生异常,文件都将被关闭。如果您需要当前拥有的详细错误输出,请继续使用当前的 try 块。大多数人会更喜欢 with 的原因是发生的任何错误都会有详细的描述和发生错误的行号,因此您基本上可以通过更少的工作获得所有必要的信息。

这里有一些额外的资源可以帮助您理解 with 和上下文管理器: