对于系统资源如文件、数据库连接、socket 而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭(断开)该资源。
如何正确的关闭一个文件呢?
1.普通版
def
test0
(
)
:
f
=
open
(
"1.txt"
,
"w"
)
f
.
write
(
"0000"
)
f
.
close
(
)
2.进阶版
def
test1
(
)
:
f
=
open
(
"1.txt"
,
"w"
)
try
:
f
.
write
(
"111111"
)
except
Exception
:
print
(
"ERROR"
)
finally
:
f
.
close
(
)
3.高级版
def
test2
(
)
:
with
open
(
"1.txt"
,
"w"
)
as
f
:
f
.
write
(
"2222"
)
使用with关键字的方法更为简洁,它的实现原理是什么,这就涉及到上下文管理器。
任何实现了
__enter__()
和
__exit__()
方法的对象都可称之为上下文管理器
4.用类还原with的实现原理
class
Test4
(
object
)
:
def
__init__
(
self
,
file_name
,
mode
)
:
self
.
file_name
=
file_name
self
.
mode
=
mode
def
__enter__
(
self
)
:
self
.
f
=
open
(
self
.
file_name
,
self
.
mode
)
return
self
.
f
def
__exit__
(
self
,
*
args
)
:
self
.
f
.
close
(
)
with
Test4
(
"1.txt"
,
"w"
)
as
f
:
f
.
write
(
"4444"
)
"""
首先Test4("1.txt", "w")初始化实例对象,
然后with会寻找类中是否有__enter__ 和 __exit__,
如果有则调用__enter__函数,
最后__enter__() 方法返回资源对象,这里就是你将要打开
的那个文件对象,__exit__() 方法处理一些清除工作。
"""
5.使用contextmanager装饰器,实现with功能
from
contextlib
import
contextmanager
"""
Python 还提供了一个 contextmanager 的装饰器,更进一步简化
了上下文管理器的实现方式。通过 yield 将函数分割成两部分,yield 之前的
语句在 __enter__ 方法中执行,yield 之后的语句在 __exit__ 方法中执行。
紧跟在 yield 后面的值是函数的返回值。
"""
@contextmanager
def
test5
(
path
,
mode
)
:
f
=
open
(
path
,
mode
)
yield
f
f
.
close
(
)
with
test5
(
'out.txt'
,
'w'
)
as
f
:
f
.
write
(
"5555"
)
总结:
Python 提供了 with 语法用于简化资源操作的后续清除操作,是 try/finally 的替代方法,实现原理建立在上下文管理器之上。此外,Python 还提供了一个 contextmanager 装饰器,更进一步简化上下管理器的实现方式。