我知道with
语句可以帮助你解决这个问题:
try:
f = open(my_file)
do_stuff_that_fails()
except:
pass
finally:
f.close()
分为:
with open(my_file) as f:
do_stuff_that_fails()
但那怎么样更好?您仍然需要处理无法打开文件的情况(比如提示用户告诉他他没有权限),所以实际上你有:
try:
with open(my_file) as f:
do_stuff_that_fails()
except (IOError, OSError, Failure) as e:
do_stuff_when_it_doesnt_work()
相当于:
try:
f = open(my_file)
do_stuff_that_fails()
except (IOError, OSError, Faillure) as e:
do_stuff_when_it_doesnt_work()
finally:
f.close()
是的,你获得了两行,但是你添加了一个嵌套级别,这使得它更容易阅读。 with
语句的目的是为了节省两行还是我遗漏了什么?
为此添加一个关键字似乎很多,所以我觉得有一些语法来处理额外的尝试/除了我不知道的。
答案 0 :(得分:34)
首先,它有助于防止您在try ... finally ...
示例中引入的问题。
您构建它的方式,如果在尝试打开文件时抛出异常,那么您永远不会将打开的文件绑定到名称f
,从而导致NameError
中的finally
f
子句(如果with
从未在范围内绑定)或完全意外的事情(如果有)。
正确的结构(相当于f = open(my_file)
try:
do_stuff_that_fails()
finally:
f.close()
)是:
except
(注意 - 如果你无事可做的话,不需要try:
f = open(my_file)
try:
do_stuff_that_fails()
except EXPECTED_EXCEPTION_TYPES as e:
do_stuff_when_it_doesnt_work()
finally:
f.close()
except (IOError, OSError) as e:
do_other_stuff_when_it_we_have_file_IO_problems()
条款。
你的第二个例子同样是错误的,应该结构如下:
f.close()
第二个是(如另一个答案所述)你不能忘记致电with
。
decimal
语句管理上下文,其中一些可能是资源,但有些则不是。例如,它还与os.walk
一起用于为特定代码块建立小数上下文。
最后(回复你对前一个答案的评论)你不应该依赖refcount语义来处理Python中的资源。 Jython,IronPython和PyPy都有非引用语义,并且没有什么可以防止CPython以其他方式运行(尽管在不久的将来它不太可能)。在紧密循环(例如{{1}})中,如果在具有不同行为的VM上运行依赖于refcount语义的代码,则很容易用完文件句柄。
答案 1 :(得分:16)
在您给出的示例中,不更好。最好的做法是尽可能地捕获异常,以避免捕获相同类型的无关异常。
try:
file = open(...)
except OpenErrors...:
# handle open exceptions
else:
try:
# do stuff with file
finally:
file.close()
由于不幸的是,with
statement不允许您捕获在评估期间抛出的异常。在邮件列表中有一个suggestion来为此效果添加异常处理:
with open(...) as file:
# do stuff with file
except OpenErrors...:
# handle open exceptions
但这是shot down。
最后值得注意的是,您可以直接进入和退出上下文管理器,如下所示:
file = open(...).__enter__()
file.__exit__(typ, val, tb)
作为一般准则,with
语句适用于不期望例外的情况,默认的“输入/打开/获取”行为就足够了。示例包括必需文件和简单锁定。
答案 2 :(得分:7)
用于资源管理 ...不是因为您对异常的反应,否则:)
没有办法忘记"使用f.close()
时with
。通过这种方式,它在C#中扮演与using
相同的角色。
快乐的编码。