有些任务可能需要事先设置并在之后清理。对于这种情况,Python 的 with 语句提供了一种非常方便的处理方式。一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。
如果不用with语句,代码如下:
代码如下:
file = open("/tmp/foo.txt")
data = file.read()
file.close()
这里有两个问题。一是你可能忘记关闭文件句柄;另一种是文件读取数据异常,没有进行处理。这是处理异常的增强版本:
代码如下:
file = open("/tmp/foo.txt")
try:
data = file.read()
finally:
file.close()
虽然这段代码工作正常,但它太冗长了。现在是尝试的时候了。 with 除了拥有更优雅的语法外,还可以处理上下文产生的异常。这是 with 版本的代码:
代码如下:
with open("/tmp /foo.txt") as file:
data = file.read()
with如何工作?
它看起来像魔术,但它不仅仅是魔术,Python 对 with 的处理很聪明。基本思想是 with 求值的对象必须有一个 __enter__() 方法和一个 __exit__() 方法。
with 后面的语句被求值后,调用返回对象的 __enter__() 方法,该方法的返回值将赋给 as 后面的变量。当 with 后面的代码块全部执行完毕后,会调用之前返回对象的 __exit__() 方法。
下面例子可以具体说明with如何工作:
代码如下:
#!/usr/bin/env python
# with_example01.py
class Sample:
def __enter__(self):
print "In __enter__()"
return "Foo"
def __exit__(self, type, value, trace):
print "In __exit__()"
def get_sample():
return Sample()
with get_sample() as sample:
print "sample:", sample
代码如下:
bash-3.2$ ./with_example01.py
In __enter__()
sample: Foo
In __exit__()
正如你看到的,
__enter__()方法被执行
__enter__()方法返回的值 - 这个例子中是"Foo",赋值给变量'sample'
执行代码块,打印变量"sample"的值为 "Foo"
__exit__()方法被调用
with 的真正强大之处在于它可以处理异常。你可能已经注意到 Sample 类的 __exit__ 方法具有三个参数 - val、type 和 trace。这些参数在异常处理中非常有用。让我们更改代码,看看它是如何工作的。
代码如下:
#!/usr/bin/env python
# with_example02.py
class Sample:
def __enter__(self):
return self
def __exit__(self, type, value, trace):
print "type:", type
print "value:", value
print "trace:", trace
def do_something(self):
bar = 1/0
return bar + 10
with Sample() as sample:
sample.do_something()
在本例中,with 后的 get_sample() 变为 Sample()。没关系,只要 with 后面的语句返回的对象有 __enter__() 和 __exit__() 方法。在本例中,Sample() 的 __enter__() 方法返回新创建的 Sample 对象并将其分配给变量 sample。
代码如下:
bash-3.2$ ./with_example02.py
type:
value: integer division or modulo by zero
trace:
Traceback (most recent call last):
File "./with_example02.py", line 19, in
sample.do_somet hing()
File "./with_example02.py", line 15, in do_something
bar = 1/0
ZeroDivisionError: integer division or modulo by zero
事实上,__exit__() 方法是在 with 后面的代码块抛出任何异常时执行的。如示例所示,当抛出异常时,关联的类型、值和堆栈跟踪将传递给 __exit__() 方法,因此会打印抛出的 ZeroDivisionError 异常。在开发库时,可以将清理资源、关闭文件等操作放在 __exit__ 方法中。
因此,Python 的 with 语句是一种有效的机制,可以让代码更加简洁,同时在发生异常时,清理工作也更加轻松。
本文为原创文章,版权归知行编程网所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ python如何使用迭代器11/12
- ♥ 什么是pythonbg09/18
- ♥ python处理绝对路径和相对路径的函数有哪些?12/08
- ♥ python编程中的常见错误10/23
- ♥ Python 字典的特点10/13
- ♥ windows下如何使用python01/14
内容反馈