我正在学习异常,因此执行一些文件操作并测试在处理 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)
当我执行此代码时,我得到以下输出:
文件未正确打开
名称错误回溯(最近一次调用(
/home/sr/Python/tcs.py in ((
--> 185 如果 os.path.exists(fp.name(
名称错误: 未定义名称"fp">
但是,如果我将文件的访问模式更改为"w",那么一切似乎都可以正常工作,正确的输出为:
文件打开成功
写入成功
文件已成功关闭
我不明白为什么"r"模式没有使文件正确打开,因此没有创建fp文件对象。请帮我解决问题。
PS:我也想知道是否有更好的方法来实现同样的事情。但这是可选的。
解释
错误与打印输出相结合应该是不言自明的:如果您无法打开文件,变量fp
就不存在。
模式'r'
指示您要打开文件进行reading。您无法读取不存在的内容,因此在处理IOError
后,您最终会转到代码中的finally
块。但是错误发生在设置fp
之前,所以没有变量fp
,因此错误。[以下解决方案]
模式'w'
指示您要从头开始打开writing。如果文件已存在,则还有一个 ppend的'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
和上下文管理器:
- 理解 Python 的 "with" 语句(来自 effbot.org(
with
的官方文档- SO 1, 2, 3, 4