韩非囚秦
——独善其身者,难成大事也。

导航

 

一、上下文管理器

  with是python实现上下文管理器的核心关键词。它能够在代码执行前和执行后做一些额外的事情。

  最常见的代码恐怕就是文件操作了。

with open("file", "r", encoding="utf-8") as f:
    data = f.read()
import functools
reader = functools.partial(open, mode="r", encoding="utf-8")
f = reader("homework/user.txt")
f.readlines()

  实际上,with语句是通过__enter__和__exit__来实现的。

class Open(object):
    def __init__(self, file, mode, encoding="GBK"):
        """初始化,生成文件句柄"""
        self.file = file
        self.mode = mode
        self.encoding = encoding
    
    def __enter__(self):
        print("__enter__ has called.")
        try:
            f = open(self.file, self.mode, self.encoding)
            return f
        except Exception as e:
            print(e)
            
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("__exit__ has called.")
        print("exc_type: ", exc_type)
        print("exc_val: ", exc_val)
        print("exc_tb: ", exc_tb)

with Open("有关协议.docx", mode='r', encoding="GBK") as f:
    data = f.readlines()

"""
__enter__ has called.
an integer is required (got type str) # 异常提示信息
__exit__ has called.
exc_type:  <class 'AttributeError'>
exc_val:  'NoneType' object has no attribute 'readlines'
exc_tb:  <traceback object at 0x110ade608>
"""

  with在开始时调用__enter__,并将结果赋给as后面的变量f。在结束时会调用__exit__,如果有异常,则会把异常类型、异常值和跟踪地址作为参数传递给__eixt__。

  如果我们自己使用with,则必须在定义的类中实现__enter__和__exit__方法。

二、contextlib模块

  python3内置了contextlib模块来帮助我们更加方便地实现上下文管理器。

import contextlib
@contextlib.contextmanager
def file_open(file_name, mode="r", encoding="utf-8"):
    print("file open")
    yield open(file_name, mode=mode, encoding=encoding)
    print("file end")

with file_open("log.txt") as f:
    print("Read file.")
    print(f)
    dic = f.read()
    print(dic)

  contextlib必须调用装饰器来装饰一个需要使用with语句的函数。在函数内部必须要使用yield将该函数变成可迭代对象。

  在with时,将yield返回值赋给as后的变量。此时已执行到yield时。f包裹的内容作为do something继续执行。最后才会执行file end。

posted on 2018-05-24 14:39  一只火眼金睛的男猴  阅读(488)  评论(0编辑  收藏  举报