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

用例:

#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")

关键输出:

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

Python之contextlib库及源码分析的更多相关文章

  1. python 从SocketServer到 WSGIServer 源码分析、

    python 下有个wsgi的封装库.wsgiref. WSGI 指的是 Web服务器网关接口(Python Web Server Gateway Interface) django的runserve ...

  2. python apschedule安装使用与源码分析

    我们的项目中用apschedule作为核心定时调度模块.所以对apschedule进行了一些调查和源码级的分析. 1.为什么选择apschedule? 听信了一句话,apschedule之于pytho ...

  3. Python之Django rest_Framework框架源码分析

    #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_fram ...

  4. 云风协程库coroutine源码分析

    前言 前段时间研读云风的coroutine库,为了加深印象,做个简单的笔记.不愧是大神,云风只用200行的C代码就实现了一个最简单的协程,代码风格精简,非常适合用来理解协程和用来提升编码能力. 协程简 ...

  5. 文件解析库doctotext源码分析

    doctotext中没有make install选项,make后生成可执行文件 在buile目录下面有.so动态库和头文件,需要的可以从这里面拷贝 build/doctotext就是可执行程序.   ...

  6. Python yield与实现(源码分析 转)

    转自:https://www.cnblogs.com/coder2012/p/4990834.html

  7. Duilib源码分析(一)整体框架

    Duilib界面库是一款由杭州月牙儿网络技术有限公司开发的界面开源库,以viksoe项目下的UiLib库的基础上开发(此后也将对UiLib库进行源码分析):通过XML布局界面,将用户界面和处理逻辑彻底 ...

  8. 【源码分析】cJSON库学习

    cJSON库是什么? cJSON是一个轻量级的json解析库.使用起来非常简单,整个库非常地简洁,核心功能的实现都在cJSON.c文件,非常适合阅读源代码来学习C语言.最近读完这个库的源码,分享自己收 ...

  9. [python] 基于词云的关键词提取:wordcloud的使用、源码分析、中文词云生成和代码重写

    1. 词云简介 词云,又称文字云.标签云,是对文本数据中出现频率较高的“关键词”在视觉上的突出呈现,形成关键词的渲染形成类似云一样的彩色图片,从而一眼就可以领略文本数据的主要表达意思.常见于博客.微博 ...

随机推荐

  1. addEventListener和attachEvent介绍, 原生js和jquery的兼容性写法

    也许很多同仁一听到事件监听,第一想到的就是原生js的 addEventListener()事件,的确如此,当然如果只是适用于现代浏览器(IE9.10.11 | ff, chorme, safari, ...

  2. [转]Linux下RPM软件包的安装及卸载 yum操作

    在 Linux 操作系统下,几乎所有的软件均通过RPM 进行安装.卸载及管理等操作.RPM 的全称为Redhat Package Manager ,是由Redhat 公司提出的,用于管理Linux 下 ...

  3. JavaScript消息机制入门篇

    JavaScript这个语言本身就是建立在一种消息机制上的,所以它很容易处理异步回调和各种事件.这个概念与普通的编程语言基础是不同的,所以让很多刚接触JavaScript的人摸不着头脑.JavaScr ...

  4. Eclipse调试C++(Cocos2dx Android )

    原文链接: http://www.cnblogs.com/zouzf/p/4202537.html 先说windows下的,mac下的在最后 环境:win8.1.java 1.5.Eclipse 4. ...

  5. React Native之Fetch简单封装、获取网络状态

    1.Fetch的使用 fetch的使用非常简单,只需传入请求的url fetch('https://facebook.github.io/react-native/movies.json'); 当然是 ...

  6. Jenkins自动打包配置

    当时也是花费了不少时间来配置Jenkins自动打包的问题,觉得还是需要记录一下. 1.安装Jenkins,这个很简单,不需要多说. 2.下载Git Plugin,Gradle Plugin,Andro ...

  7. java实现定时任务的三种方法 - 转载

    java实现定时任务的三种方法 /** * 普通thread * 这是最常见的,创建一个thread,然后让它在while循环里一直运行着, * 通过sleep方法来达到定时任务的效果.这样可以快速简 ...

  8. java 与大数据学习较好的网站

    C# C#中 Thread,Task,Async/Await,IAsyncResult 的那些事儿!https://www.cnblogs.com/doforfuture/p/6293926.html ...

  9. POJ3275:Ranking the Cows(Bitset加速floyd求闭包传递)

    Each of Farmer John's N cows (1 ≤ N ≤ 1,000) produces milk at a different positive rate, and FJ woul ...

  10. Java基础13:反射与注解详解

    Java基础13:反射与注解详解 什么是反射? 反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. Orac ...