在python中使用异常和文件时清理

时间:2009-07-19 14:12:25

标签: python exception file-io

我现在正在学习python几天,并且正在努力学习它的“精神”。 我是从C / C ++ / Java / Perl学校来的,我知道python不是C(根本就是)这就是为什么我试图理解精神来充分利用它(到目前为止很难) ...

我的问题特别关注异常处理和清理: 本文末尾的代码用于模拟文件打开/解析的相当常见的情况,如果出现错误,您需要关闭文件...

我见过的大多数样本使用try语句的'else'子句来关闭文件......这对我来说很有意义,直到我意识到错误可能是由于

  • 开口本身(在这种情况下 没有必要关闭不 打开文件)
  • 解析(其中 如果需要关闭文件)

这里的陷阱是,如果你使用try bloc的'else'子句,那么如果在解析期间发生错误,文件永远不会被关闭! 另一方面,使用'finally'子句导致额外的必要检查,因为如果在打开期间发生错误,则file_desc变量可能不存在(参见下面代码中的注释)......

这个额外的检查是低效的,并且充满了糟糕,因为任何合理的程序可能包含数百个符号并且解析dir()的结果是痛苦的...更不用说这样的语句缺乏可读性。 ..

大多数其他语言允许变量定义,这可以节省一天...但在python中,一切似乎都是隐含的......

通常,只需要声明一个file_desc变量,然后为每个任务使用许多try / catch块...一个用于打开,一个用于解析,最后一个用于关闭()...不需要嵌套它们......在这里,我不知道一种声明变量的方法......所以我在问题的开头就陷入了困境!

那么这里的python精神是什么?

  • 用两种不同的方法拆分开头/解析?怎么样?
  • 使用某种嵌套的try / except子句???怎么样?
  • 也许有一种方法可以声明file_desc变量然后就不需要额外的检查......它是否可能?希望???
  • close()语句怎么样?怎么会引起错误?

thanx为您的提示...这是示例代码:

class FormatError(Exception):
    def __init__(self, message):
        self.strerror = message
    def __str__(self):
        return repr(message)


file_name = raw_input("Input a filename please: ")
try:
    file_desc = open(file_name, 'r')
    # read the file...
    while True:
        current_line = file_desc.readline()
        if not current_line: break
        print current_line.rstrip("\n")
    # lets simulate some parsing error...
    raise FormatError("oops... the file format is wrong...")
except FormatError as format_error:
    print "The file {0} is invalid: {1}".format(file_name, format_error.strerror)
except IOError as io_error:
    print "The file {0} could not be read: {1}".format(file_name, io_error.strerror)
else:
    file_desc.close()
# finally:
#     if 'file_desc' in dir() and not file_desc.closed:
#        file_desc.close()

if 'file_desc' in dir():
    print "The file exists and closed={0}".format(file_desc.closed)
else:
    print "The file has never been defined..."

5 个答案:

答案 0 :(得分:6)

处理此问题的最简单方法是使用Python 2.5+中的文件对象context managers这一事实。您可以使用with语句输入上下文;退出此__exit__范围时,将自动调用上下文管理器的with方法。文件对象的上下文管理会自动关闭文件。

try:
    with file("hello.txt") as input_file:
        for line in input_file:
            if "hello" not in line:
                 raise ValueError("Every line must contain 'hello'!")
except IOError:
    print "Damnit, couldn't open the file."
except:
    raise
else:
    print "Everything went fine!"

open hello.txt句柄将自动关闭,with scope中的异常将在外部传播。

答案 1 :(得分:2)

只需注意:你总是可以声明一个变量,然后就会变成这样:

file_desc = None
try:
    file_desc = open(file_name, 'r')
except IOError, err:
    pass
finally:
    if file_desc:
        close(file_desc)

当然,如果您使用的是较新版本的Python,那么使用上下文管理器的构造会更好;但是,我想指出如何在Python中一般处理异常和变量范围。

答案 2 :(得分:1)

从Python 2.5开始,有一个with命令可以简化您正在与之抗争的内容。阅读更多相关信息here。这是您的代码的转换版本:

class FormatError(Exception):
    def __init__(self, message):
        self.strerror = message
    def __str__(self):
        return repr(message)


file_name = raw_input("Input a filename please: ")
with open(file_name, 'r') as file_desc:
    try:
        # read the file...
        while True:
            current_line = file_desc.readline()
            if not current_line: break
            print current_line.rstrip("\n")
        # lets simulate some parsing error...
        raise FormatError("oops... the file format is wrong...")
    except FormatError as format_error:
        print "The file {0} is invalid: {1}".format(file_name, format_error.strerror)
    except IOError as io_error:
        print "The file {0} could not be read: {1}".format(file_name, io_error.strerror)

if 'file_desc' in dir():
    print "The file exists and closed={0}".format(file_desc.closed)
else:
    print "The file has never been defined..."

答案 3 :(得分:0)

好的,我是个笨蛋。  编辑:BTW,对于那些在我发布此帖时已经回答的人来说,还有很多。

下面的代码可以解决问题。 您必须使用'with as'语句创建一个嵌套块,以确保清除该文件:

class FormatError(Exception):
    def __init__(self, message):
        self.strerror = message
    def __str__(self):
        return repr(message)


file_name = raw_input("Input a filename please: ")
try:
    #
    # THIS IS PYTHON'S SPIRIT... no else/finally
    #
    with open(file_name, 'r') as file_desc:
        # read the file...
        while True:
            current_line = file_desc.readline()
            if not current_line: break
            print current_line.rstrip("\n")
        raise FormatError("oops... the file format is wrong...")
    print "will never get here"
except FormatError as format_error:
    print "The file {0} is invalid: {1}".format(file_name, format_error.strerror)
except IOError as io_error:
    print "The file {0} could not be read: {1}".format(file_name, io_error.strerror)

if 'file_desc' in dir():
    print "The file exists and closed={0}".format(file_desc.closed)
else:
    print "The file has never been defined..."

答案 4 :(得分:0)

关闭我的知识永远不会返回错误。

实际上,文件句柄将在收集垃圾时关闭,因此您不必在Python中显式执行。虽然这样做仍然是很好的编程,显然。