`
luozhaoyu
  • 浏览: 347199 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

从with关键字到编写自己简单的ContextManager(一)

阅读更多
本文先介绍with表达式,然后再试图用with以及装饰器等知识实现自己的ContextManager

with可以干什么?我的理解是简化try except finally的工作,比如打开文件操作符,读文件,捕捉异常,最后关闭。这个例子是with最最常用的方法了,满大街都可以找到这个例子。
除文件open操作之外,其实其它很多操作也可以掐头去尾,留下中间关键操作就行。
那么该如何实现呢?按照python文档解释,只要实现__enter__和__exit__两个函数就可以。
很简单:
class ConMgr(object):
    def __init__(self):
        print("__init__ called")
    
    
    def __call__(self, *args):
        print("__call__ called")
        #: 可以把传进来的参数保存着,在with开始时运行
        self.args = args
        return self
        
    
    def __enter__(self):
        # 打印之前传进来的参数
        print("__enter__ called", self.args)
        return 'abcd'

        
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("__exit__ called: exc_type = %s exc_val = %s exc_tb = %s "\
              % (exc_type, exc_val, exc_tb))
        return "exited"


def test1():
    c = ConMgr()
    with c('pppp') as tmp:
        print(tmp)
        print("haha")
        assert 1>2
        print(3)

test1()

输出结果是:
__init__ called
__call__ called
('__enter__ called', ('pppp',))
abcd
haha
__exit__ called: exc_type = <type 'exceptions.AssertionError'> exc_val =  exc_tb = <traceback object at 0x7f911003b128> 

首先请注意,这里的c()是类的一个实例,就是一个普通类,而不是generator。当c('pppp')执行时,调用了__call__函数,__call__函数赶紧把传入的参数保存了下来,等进了with块之后,调用__enter__之时再把参数放出来。
另外__call__函数一定要返回self,因为with块运行完了之后,将会调用self.__exit__()如果不返回self将找不到__exit__函数。
然后就是as语句的tmp值实际上是__enter__的返回值,返回什么都可以,无所谓的,哪怕传个闭包。这里的好主意是把之前的args可以传给tmp。
最后请仔细看,当assert 1>2发生错误之后,with块没有执行完就调用__exit__函数了。通过这个函数的参数,我们来实现异常处理。

接下来介绍下python的contextlib这个模块。
可能有朋友不知到,这个模块没有主轴功能,主要是围绕with语句,提供了一些方便的util函数操作。
这个模块里面有一个contextmanager的装饰器,它可以省掉我们之前那么麻烦创建一个class然后补上__enter__和__exit__的过程,它利用工厂模式生成一个generator,然后就可以方便的使用with语句了。
关于官方contextlib模块里面的功能,我想自己能不能做一个山寨版出来,详细见下文
0
0
分享到:
评论

相关推荐

    Python with关键字,上下文管理器,@contextmanager文件操作示例

    在Python编程语言中,`with`关键字和上下文管理器是高效、安全处理资源的关键工具,特别是涉及到文件操作。它们确保了资源(如文件)在使用完毕后会被正确关闭,即使在执行过程中出现了异常。本篇文章将深入探讨`...

    Python库 | scope_injected_contextmanager-0.0.2.tar.gz

    例如,它可能提供了一个`@contextmanager`装饰器,允许开发人员通过简单的生成器函数定义上下文管理器。 在使用这个库时,开发人员可以将需要管理资源的代码封装到`with`语句中,确保资源的生命周期得到正确的控制...

    Baekjoon_Online_Judge_Python:使用Python的알고리with제with이

    在Python中,"with"关键字用于创建一个上下文管理器,它会自动处理对象的获取和释放。例如,当我们需要读取或写入文件时,可以使用"with open() as f:"的形式来操作。这样,无论代码是否抛出异常,文件都会在离开...

    Python中的上下文管理器和with语句的使用

    此外,Python 的 `contextlib` 模块提供了一个 `contextmanager` 装饰器,可以简化上下文管理器的编写,通过 `yield` 语句划分 `__enter__` 和 `__exit__` 的逻辑。 ```python from contextlib import ...

    Professional-Python.pdf.pdf

    通过以上内容,读者可以了解到文档涵盖了Python编程的高级概念和实践,从函数的高级用法,到面向对象编程的深入探讨,再到数据处理的策略,以及对Python版本差异的比较、测试、命令行工具的使用,以及异步编程和编程...

    python_context_management_sandbox:研究Python上下文管理器,以便编写代码可能更优雅

    在这个例子中,`open('file.txt', 'r')`返回一个实现了上下文管理器的对象,我们在`with`关键字后将其赋值给变量`f`。当`with`块结束时,`__exit__`方法会被自动调用,确保文件被正确关闭,即使在处理文件时发生异常...

    python面试合集资源包

    以下是一份详尽的Python面试知识点概述,涵盖从基础到高级的主题。 1. **Python基础知识** - Python的哲学:简洁、可读性强的语法,"There should be one-- and preferably only one --obvious way to do it." - ...

    Python contextlib模块使用示例

    `contextlib.nested`函数用于同时管理多个上下文管理器,但请注意,自Python 3.7起,它已经被弃用,取而代之的是使用`async with`和`await`关键字的嵌套上下文管理器。然而,对于旧版本的Python,`nested`可以这样...

    Python进阶

    在这个例子中,`print_kwargs`函数可以接受任意数量的关键字参数,并且这些参数会被打包成一个字典`kwargs`。 ##### 使用args和*kwargs来调用函数 有时候我们需要将一组参数传递给一个期望接收不同形式参数的函数...

    python 中的9个实用技巧,助你提高开发效率

    这种方式在处理大数据集时尤其有用,因为它避免了一次性加载所有数据到内存中的需求。 通过以上介绍的九个技巧,我们可以看出Python语言提供了许多强大而灵活的功能,帮助开发者编写出高效且易于维护的代码。希望...

    holbertonschool-higher_level_programming

    6. **迭代器和生成器**:迭代器允许遍历任何可迭代对象,而生成器则是一种惰性计算的迭代器,可以通过 yield 关键字创建。使用生成器可以节省内存,尤其在处理大量数据时。 7. **装饰器**:装饰器是 Python 的一种...

Global site tag (gtag.js) - Google Analytics