Python之contextlib库及源码分析建议收藏

AbstractContextManager(abc.ABC)上下文管理抽象类,子类必须实现__enter__(self)、__exit__(self)ContextDecorator(objec

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

Python之contextlib库及源码分析建议收藏此处内容已经被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“”,获取验证码。在微信里搜索“”或者“”或者微信扫描右侧二维码都可以关注本站微信公众号。

Utilities for
with-statement contexts

  __all__ = [“contextmanager”, “closing”, “AbstractContextManager”,

               ”ContextDecorator”, “ExitStack”, “redirect_stdout”,

               ”redirect_stderr”, “suppress”]

AbstractContextManager(abc.ABC)

  上下文管理抽象类,子类必须实现__enter__(self)、__exit__(self)

class AbstractContextManager(abc.ABC):

    """An abstract base class for context managers."""

    def __enter__(self):
        """Return `self` upon entering the runtime context."""
        return self

    @abc.abstractmethod
    def __exit__(self, exc_type, exc_value, traceback):
        """Raise any exception triggered within the runtime context."""
        return None

    @classmethod
    def __subclasshook__(cls, C):
        if cls is AbstractContextManager:
            if (any("__enter__" in B.__dict__ for B in C.__mro__) and
                any("__exit__" in B.__dict__ for B in C.__mro__)):
                return True
        return NotImplemented

ContextDecorator(object)

  上下文管理基类或mixin类,该类可以像装饰器一样工作,提供你需要实现的任何辅助功能

class ContextDecorator(object):
    "A base class or mixin that enables context managers to work as decorators."

    def _recreate_cm(self):
        """Return a recreated instance of self.

        Allows an otherwise one-shot context manager like
        _GeneratorContextManager to support use as
        a decorator via implicit recreation.

        This is a private interface just for _GeneratorContextManager.
        See issue #11647 for details.
        """
        return self

    def __call__(self, func):
        @wraps(func)
        def inner(*args, **kwds):
            with self._recreate_cm():
                return func(*args, **kwds)
        return inner

_GeneratorContextManager(ContextDecorator, AbstractContextManager)

  contextmanager装饰器的包装函数提供以下方法:

  _recreate_cm(重新生成新对像),self.__class__(*args, **kwds)

  __enter__上下文管理进入函数

  __exit__上下文管理退出函数

  可以根据ContextDecorator实现任何想实现的辅助功能

class _GeneratorContextManager(ContextDecorator, AbstractContextManager): """Helper for @contextmanager decorator.""" def __init__(self, func, args, kwds): self.gen = func(*args, **kwds) logger.info("get generator by with:{}".format(self.gen)) self.func, self.args, self.kwds = func, args, kwds # Issue 19330: ensure context manager instances have good docstrings doc = getattr(func, "__doc__", None) #得到函数文档,第三个参数为默认参数 logger.info("doc:{}".format(doc)) if doc is None: doc = type(self).__doc__ self.__doc__ = doc # Unfortunately, this still doesn't provide good help output when # inspecting the created context manager instances, since pydoc # currently bypasses the instance docstring and shows the docstring # for the class instead. # See http://bugs.python.org/issue19404 for more details. def _recreate_cm(self): # _GCM instances are one-shot context managers, so the # CM must be recreated each time a decorated function is # called return self.__class__(self.func, self.args, self.kwds) def __enter__(self): logger.info("__enter__:you can add you method") @ContextDecorator() def testfun(*args, **kwds): logger.info("@ContextDecorator():testfun test success") testfun("hello") try: return next(self.gen) except StopIteration: raise RuntimeError("generator didn't yield") from None def __exit__(self, type, value, traceback): logger.info("__exit__") logger.info("type:{}".format(type)) if type is None: try: next(self.gen) except StopIteration: return else: raise RuntimeError("generator didn't stop") else: if value is None: # Need to force instantiation so we can reliably # tell if we get the same exception back value = type() try: self.gen.throw(type, value, traceback) raise RuntimeError("generator didn't stop after throw()") except StopIteration as exc: # Suppress StopIteration *unless* it's the same exception that # was passed to throw(). This prevents a StopIteration # raised inside the "with" statement from being suppressed. return exc is not value except RuntimeError as exc: # Don't re-raise the passed in exception. (issue27112) if exc is value: return False # Likewise, avoid suppressing if a StopIteration exception # was passed to throw() and later wrapped into a RuntimeError # (see PEP 479). if exc.__cause__ is value: return False raise except: # only re-raise if it's *not* the exception that was # passed to throw(), because __exit__() must not raise # an exception unless __exit__() itself failed. But throw() # has to raise the exception to signal propagation, so this # fixes the impedance mismatch between the throw() protocol # and the __exit__() protocol. #  if sys.exc_info()[1] is not value: raise

装饰器contextmanager

def contextmanager(func): """@contextmanager decorator. Typical usage: @contextmanager def some_generator(<arguments>): <setup> try: yield <value> finally: <cleanup> This makes this: with some_generator(<arguments>) as <variable>: <body> equivalent to this: <setup> try: <variable> = <value> <body> finally: <cleanup> """ @wraps(func) def helper(*args, **kwds): return _GeneratorContextManager(func, args, kwds) return helper

用例:

Python之contextlib库及源码分析建议收藏
Python之contextlib库及源码分析建议收藏

#coding = utf-8 import abc from functools import wraps import logging logging.basicConfig(level=logging.INFO, filename="logging.txt", filemode="w+", \ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) class AbstractContextManager(abc.ABC): """An abstract base class for context managers.""" def __enter__(self): """Return `self` upon entering the runtime context.""" return self @abc.abstractmethod def __exit__(self, exc_type, exc_value, traceback): """Raise any exception triggered within the runtime context.""" return None @classmethod def __subclasshook__(cls, C): if cls is AbstractContextManager: if (any("__enter__" in B.__dict__ for B in C.__mro__) and any("__exit__" in B.__dict__ for B in C.__mro__)): return True return NotImplemented class ContextDecorator(object): "A base class or mixin that enables context managers to work as decorators." def _recreate_cm(self): """Return a recreated instance of self. Allows an otherwise one-shot context manager like _GeneratorContextManager to support use as a decorator via implicit recreation. This is a private interface just for _GeneratorContextManager. See issue #11647 for details. """ return self def __call__(self, func): #logger.info("ContextDecorator func:{}".format(func))  @wraps(func) def inner(*args, **kwds): #with self._recreate_cm(): logger.info("you can do something in decorator") return func(*args, **kwds) return inner class _GeneratorContextManager(ContextDecorator, AbstractContextManager): """Helper for @contextmanager decorator.""" def __init__(self, func, args, kwds): self.gen = func(*args, **kwds) logger.info("get generator by with:{}".format(self.gen)) self.func, self.args, self.kwds = func, args, kwds # Issue 19330: ensure context manager instances have good docstrings doc = getattr(func, "__doc__", None) #得到函数文档,第三个参数为默认参数 logger.info("doc:{}".format(doc)) if doc is None: doc = type(self).__doc__ self.__doc__ = doc # Unfortunately, this still doesn't provide good help output when # inspecting the created context manager instances, since pydoc # currently bypasses the instance docstring and shows the docstring # for the class instead. # See http://bugs.python.org/issue19404 for more details. def _recreate_cm(self): # _GCM instances are one-shot context managers, so the # CM must be recreated each time a decorated function is # called return self.__class__(self.func, self.args, self.kwds) def __enter__(self): logger.info("__enter__:you can add you method") @ContextDecorator() def testfun(*args, **kwds): logger.info("@ContextDecorator():testfun test success") testfun("hello") try: return next(self.gen) except StopIteration: raise RuntimeError("generator didn't yield") from None def __exit__(self, type, value, traceback): logger.info("__exit__") logger.info("type:{}".format(type)) if type is None: try: next(self.gen) except StopIteration: return else: raise RuntimeError("generator didn't stop") else: if value is None: # Need to force instantiation so we can reliably # tell if we get the same exception back value = type() try: self.gen.throw(type, value, traceback) raise RuntimeError("generator didn't stop after throw()") except StopIteration as exc: # Suppress StopIteration *unless* it's the same exception that # was passed to throw(). This prevents a StopIteration # raised inside the "with" statement from being suppressed. return exc is not value except RuntimeError as exc: # Don't re-raise the passed in exception. (issue27112) if exc is value: return False # Likewise, avoid suppressing if a StopIteration exception # was passed to throw() and later wrapped into a RuntimeError # (see PEP 479). if exc.__cause__ is value: return False raise except: # only re-raise if it's *not* the exception that was # passed to throw(), because __exit__() must not raise # an exception unless __exit__() itself failed. But throw() # has to raise the exception to signal propagation, so this # fixes the impedance mismatch between the throw() protocol # and the __exit__() protocol. #  if sys.exc_info()[1] is not value: raise def contextmanager(func): """@contextmanager decorator. Typical usage: @contextmanager def some_generator(<arguments>): <setup> try: yield <value> finally: <cleanup> This makes this: with some_generator(<arguments>) as <variable>: <body> equivalent to this: <setup> try: <variable> = <value> <body> finally: <cleanup> """ @wraps(func) def helper(*args, **kwds): return _GeneratorContextManager(func, args, kwds) return helper @contextmanager def file_open(path): ''' file open test''' try: f_obj = open(path,"w") yield f_obj except OSError: print("We had an error!") finally: print("Closing file") f_obj.close() if __name__ == "__main__": with file_open("contextlibtest.txt") as fobj: fobj.write("Testing context managers") logger.info("write file success")

View Code

关键输出:

2018-03-22 15:36:43,249 - __main__ - INFO - get generator by with:<generator object file_open at 0x01DE4870> 2018-03-22 15:36:43,249 - __main__ - INFO - doc: file open test 2018-03-22 15:36:43,249 - __main__ - INFO - __enter__:you can add you method 2018-03-22 15:36:43,249 - __main__ - INFO - you can do something in decorator 2018-03-22 15:36:43,249 - __main__ - INFO - @ContextDecorator():testfun test success 2018-03-22 15:36:43,249 - __main__ - INFO - write file success 2018-03-22 15:36:43,249 - __main__ - INFO - __exit__ 2018-03-22 15:36:43,249 - __main__ - INFO - type:None

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/120185.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • UVa 414 – Machined Surfaces

    UVa 414 – Machined Surfaces题目:n个由X和空格组成的串,两边有至少一个X,将n个串压缩,每次每行消除一个空格,问到不能消除时剩余的空格。分析:简单题。统计全体空格数sum_b和最少空格数min_b,则结果就是sum_b-n*min_b。注意:利用gets或者getline读入串。#include#include#include#includeusingnamespacestd;

  • js 做返回顶部效果

    js 做返回顶部效果涉及的知识点: font-awesome字体图标;使用的cdn。 window.onload窗口加载完成事件;如果js代码写在body标签之前,则所有的js都要写在window.onload的事件中;即等待窗口加载完成之后再执行! window.onscroll窗口滚动事件 窗口滚动的距离      document.documentEleme…

  • 【Linux】面试题(2021最新版)

    【Linux】面试题(2021最新版)Linux的体系结构Linux-查找特定文件Linux-对日志内容做统计Linux-批量替换文件内容

  • phpstorm激活码2022激活_在线激活

    (phpstorm激活码2022激活)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html…

  • 单源最短路径dijkstra算法_dijkstra是谁

    单源最短路径dijkstra算法_dijkstra是谁年轻的探险家来到了一个印第安部落里。在那里他和酋长的女儿相爱了,于是便向酋长去求亲。酋长要他用 10000 个金币作为聘礼才答应把女儿嫁给他。探险家拿不出这么多金币,便请求酋长降低要求。酋长说:”嗯,如果你能够替我弄到大祭司的皮袄,我可以只要 8000 金币。如果你能够弄来他的水晶球,那么只要 5000 金币就行了。”探险家就跑到大祭司那里,向他要求皮袄或水晶球,大祭司要他用金币来换,或者替他弄来其他的东西,他可以降低价格。探险家于是又跑到其他地方,其他人也提出了类似的要求,或者直接用金币换,或

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号