文章

Python练习-常用内建模块contextlib

最近很忙,距离上一篇博文过去已经10多天了,不想荒废。今天继续学习Python常用内置模块contextlib。其实主要是学习了contextlib这个模块中@contextmanager这个注解的使用。

前面学习过,在Python可以使用with语句自动的进行如文件处理时的打开和关闭操作。其实从原理上讲,在Python任何实现了__enter__和__exit__方法的类都可以使用with语句进行自动操作。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 本部分练习contextlib 内置模块

class ContextDemo(object):

    def __init__(self, name):
        self.jobname = name
        print("Init")

    def __enter__(self):
        print("Open")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Exit")

    def dowork(self):
        print("Do %s here." % self.jobname)


with ContextDemo("DemoJob") as cd:
    cd.dowork()

输出如下:

1
2
3
4
Init
Open
Do DemoJob here.
Exit

每次编写enter和exit会很犯错,可通过contextlib中的contextmanager注解快速实现同样的功能,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 写enter和exit仍然繁琐,通过contextlib有更简便的写法
from contextlib import contextmanager


class ContextManagerDemo(object):

    def __init__(self, name):
        self.name = name

    def dowork(self):
        print('Do %s here....' % self.name)


@contextmanager
def do_cmd_job(name):
    print('Open')
    q = ContextManagerDemo(name)
    # 通过yield把q输出
    yield q
    print('Exit')


with do_cmd_job("CMDemoJob") as cmd:
    cmd.dowork()

输入如下:

1
2
3
Open
Do CMDemoJob here....
Exit

这里contextmanager注解,有点像Java中的切片编程,可以讲真正要执行的函数“夹”在事前和事后处理中间。

如果一个对象没有实现上下文,我们就不能把它用于with语句。这个时候,可以用closing()来把该对象变为上下文对象。例如,用with语句使用urlopen(),这里其实closing也是利用contextmanager实现的,会默认调用传入对象的close方法,因此未实现close方法的类是无法使用closing函数的,会报错。这里通过源码可以看到urlopen对象是有close方法的。

1
2
3
4
5
6
from contextlib import closing
from urllib.request import urlopen

with closing(urlopen("http://www.coderli.com")) as page:
    for line in page:
        print(line)

输出如下:

1
2
Init
Do Closing here.
本文由作者按照 CC BY 4.0 进行授权