• Python中使用with语句同时打开多个文件


    下午小伙伴问了一个有趣的问题, 怎么用 Python 的 with 语句同时打开多个文件?

    首先, Python 本身是支持同时在 with 中打开多个文件的

    with open('a.txt', 'r') as a, open('b.txt', 'r') as b:
        print(a.read())
        print(b.read())
    
    

    当然, 小伙伴的问题不可能这么简单, 他需要从打开一个列表中的所有文件, 而不是打开固定的一个文件, 这时候上面的语法显然就没法满足要求了. 幸运的是 with 语句是遵循协议的, 我们只要自定义出__enter__方法和__exit__方法就可以使用 with 语句打开自定义的类.比如我们定义以下类, 用于同时打开多个文件:

    #!/usr/bin/env python
    # coding: utf-8
    
    
    class open_many:
    
        def __init__(self, files=None, mode='r'):
            if files is None:
                self._files = []
            else:
                self._files = files
            self.mode = mode
            self.fds = []  # fd is short for file descriptor
    
        def __enter__(self):
            print('-->enter')
            for f in self._files:
                print('-->opening file')
                self.fds.append(open(f, self.mode))
            return self.fds
    
        def __exit__(self, exc_type, exc_val, traceback):
            print('-->exit')
            for fd in self.fds:
                print('-->closing file')
                fd.close()
            if exc_type == ValueError:
                print('-->exception: ' + str(exc_val))
                return True
    
    
    if __name__ == '__main__':
        print('')
        with open_many(['a.txt', 'b.txt'], 'r') as files:
            for f in files:
                print f.read()
        print('')
        with open_many() as files:
            raise ValueError('captured')
        print('')
        with open_many() as files:
            raise Exception('uncaptureable')
    
    

    运行结果如下:

    result

    其中__enter__方法会被进入 with 语句时调用, 返回值会作为 as 后面变量的值. __exit__方法的三个参数分别是发生的异常的类型, 异常变量, 和发生异常时的 traceback. 如果在__exit__中能够处理异常, 那么应该返回True, 否则应该返回 False. 需要注意的是, 并不需要再次把异常抛出. 这里处理的异常实在 with 语句块中发生的异常

    显然为了使用 with 还需要定义一个类有点过于复杂了, Python 还提供了另一种方法, 使用 contextlib.contextmanager 装饰器和生成器来实现

    #!/usr/bin/env python
    # coding: utf-8
    
    
    from contextlib import contextmanager
    
    
    @contextmanager
    def open_many(files=None, mode='r'):
        if files is None:
            files = []
        try:  #相当于__enter__
            fds = []
            for f in files:
                fds.append(open(f, mode))
            yield fds 
        except ValueError as e:
            print(e)
        finally:  #相当于__exit__
            for fd in fds:
                fd.close()
    
    
    if __name__ == '__main__':
        with open_many(['a.txt', 'b.txt'], 'r') as files:
            for f in files:
                print(f.read())
    

    此外, contextlib 中还提供了 closing 语句, 使用这个语句可以自动调用类的 close 方法.

    #!/usr/bin/env python
    # coding: utf-8
    
    
    from contextlib import closing
    
    
    class Connection:
    
        def open(self):
            print('opened')
    
        def close(self):
            print('closed')
    
    
    if __name__ == '__main__':
        with closing(Connection()) as con:
            con.open()
            # do stuff with con
    
  • 相关阅读:
    Selenium RC和WebDriver的实现区别(一)
    布线问题
    C语言播放音乐
    圈水池
    双向BFS
    Asp.net MVC3 Razor中的扩展HtmlHelper的返回类型问题
    使用Visual Studio 利用WinGDB编译和远程调试嵌入式Linux的程序
    IoTSharp部署教程Sqlite分表篇
    sql 2005性能调优
    Sql养成一个好习惯是一笔财富
  • 原文地址:https://www.cnblogs.com/ospider/p/5267766.html
Copyright © 2020-2023  润新知