上下文管理 & contextlib.contextmanager & functool.total_ordering

  

文件I/O操作可以对文件对象使用上下文管理,使用with as语法

with open('file') as f:
    pass

 

上下文管理对象

当一个对象同时实现了__enter__()和__exit__()方法,就属于上下文管理对象

  • __enter__进入与此对象相关的上下文,如果存在该方法,with语法会把该方法的返回值作为绑定到as 字句中指定的变量上
  • __exit__ 退出与此对象相关的上下文
class Owl:

    def __init__(self):
        print('init')
        
    def __enter__(self):
        print('enter')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(self.__class__.__name__)

with Owl() as f:
    pass

 

 

class Owl:

    def __init__(self):
        print('init')

    def __enter__(self):
        print('enter')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(self.__class__.__name__)

o=Owl()

with o as f: # f 为__enter__()返回值
    print(f==o)
    print(f is o)
    print('o => {}'.format(o))
    print('f => {}'.format(f))

 

open内建函数返回的object实现了__enter__()和__exit__()方法

实例化对象的时候,并不会调用__enter__(),进入with语句块调用__enter__方法,然后执行语句体,最后离开语句块with的时候,调用__exit__方法

 

上下文管理的安全性

class Owl:

    def __init__(self):
        print('init')

    def __enter__(self):
        print('enter')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(self.__class__.__name__)

o=Owl()

import sys
with o as f: # f 为__enter__()返回值
    sys.exit(256)
    raise Exception('raise Exception')
    print(f==o)
    print(f is o)
    print('o => {}'.format(o))
    print('f => {}'.format(f))

sys.exit()和raise Exception()都不会阻止__exit__的执行 

__enter__方法返回值就是上下文中使用的对象,with语法会把它的返回值赋给as字句变量

 

__enter__ 和 __exit__参数

__enter__没有其他参数

__exit__有三个参数exc_type,exc_val,exc_tb

三个参数都与异常有关

如果该上下文退出时没有异常,则这三个参数都为None

如果有异常,则参数意义如下:

  • exc_type       异常类型 <class 'Exception'>
  • exc_val          异常值,类型为<class 'Exception'>
  • exc_tb           异常的追踪信息 <traceback object at 0x000001AE8E25B600>
class Owl:

    def __init__(self):
        print('init')

    def __enter__(self):
        print('enter')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(self.__class__.__name__+'*'*40)
        print(exc_type)
        print(exc_val,type(exc_val))
        print(exc_tb)
        return 0

o=Owl()

import sys
with o as f: # f 为__enter__()返回值
    # sys.exit(256)
    raise Exception('raise Exception')
    print(f==o)
    print(f is o)
    print('o => {}'.format(o))
    print('f => {}'.format(f))

print('outer scope')

 

时间装饰器函数

import time,datetime
from functools import wraps

def Cursitor(fn):
    @wraps(fn)
    def wrapper(*args,**kwargs):
        germ=datetime.datetime.now()
        ret=fn(*args,**kwargs)
        delta=(datetime.datetime.now()-germ).total_seconds()
        print('{} consume {}'.format(fn.__name__,delta))
        return ret
    return wrapper

@Cursitor
def add(x,y):
    time.sleep(2)
    return x+y

print(add(8,7))

 

上下文实现

import time,datetime
from functools import wraps

def cursitor(fn):
    @wraps(fn)
    def wrapper(*args,**kwargs):
        germ=datetime.datetime.now()
        ret=fn(*args,**kwargs)
        delta=(datetime.datetime.now()-germ).total_seconds()
        print('{} consume {}'.format(fn.__name__,delta))
        return ret
    return wrapper

@cursitor
def add(x,y):
    time.sleep(2)
    return x+y

class Cursitor:
    def __init__(self,fn):
        self.fn=fn

    def __enter__(self):
        self.germ=datetime.datetime.now()
        return self.fn
        # return self

    def __exit__(self,exc_type,exc_val,exc_tb):
        self.delta=(datetime.datetime.now()-self.germ).total_seconds()
        print('{} consume {} context'.format(self.fn.__name__,self.delta))
        return None

# with Cursitor(add):
#     print(add(8,8))
    
with Cursitor(add) as f:
    print(f(8,9))
import time,datetime
from functools import wraps

def cursitor(fn):
    @wraps(fn) # wraps(fn)(wrapper)
    def wrapper(*args,**kwargs):
        germ=datetime.datetime.now()
        ret=fn(*args,**kwargs)
        delta=(datetime.datetime.now()-germ).total_seconds()
        print('{} consume {}'.format(fn.__name__,delta))
        return ret
    return wrapper

@cursitor
def add(x,y):
    time.sleep(2)
    return x+y

class Cursitor:
    def __init__(self,fn):
        print('init')
        self.fn=fn
        # self.__doc__=fn.__doc__
        # self.__name__=fn.__name__

    def __enter__(self):
        self.germ=datetime.datetime.now()
        # return self.fn
        return self

    def __exit__(self,exc_type,exc_val,exc_tb):
        self.delta=(datetime.datetime.now()-self.germ).total_seconds()
        print('{} consume {} context'.format(self.fn.__name__,self.delta))
        return None

    def __call__(self,*args,**kwargs):
        wraps(self.fn)(self)
        germ=datetime.datetime.now()
        ret=self.fn(*args,**kwargs)
        delta=(datetime.datetime.now()-germ).total_seconds()
        print('{} consume {} __call__'.format(self.fn.__name__,delta))
        return ret

# with Cursitor(add):
#     print(add(8,8))

# with Cursitor(add) as f:
#     print(f(8,9))

# c=Cursitor(add)
# with c:
#     print(c(7,9))

# with Cursitor(add) as f:
#     print(f(5,9))

# c=Cursitor(add)
# with c as f:
#     print(f(4,9))

@Cursitor
def add(x,y): # add=Cursitor(add)
    'add doc'
    time.sleep(2)
    return x+y
print(add)
print(add(4,8))
print(add.__doc__)
print(add.__name__)
print(add.__dict__)

 

contextlib.contextmanager

是一个装饰器实现上下文管理,装饰一个函数,不用实现像类一样__enter__和__exit__方法

对下面的函数有要求,必须有yield,也就是这个函数必须返回一个生成器,且只有yield一个值 

import contextlib
@contextlib.contextmanager
def ore():
    # print('__enter__') # amount to __enter__()
    # yield 4,6
    # print('__exit__') # amount to __exit__()
    print('__enter__')
    try:
        yield 4,9
    finally:
        print('__exit__')

with ore() as f:
    raise Exception
    print(f)

在yield发生处为生成器函数增加了上下文管理

import contextlib,datetime,time
@contextlib.contextmanager
def ore(x,y): # 为生成器函数增加了上下文管理
    germ=datetime.datetime.now()
    try:
        yield x+y # yield值只能有一个,作为__enter__方法返回值
    finally:
        delta=(datetime.datetime.now()-germ).total_seconds()
        print(delta)

with ore(8,9) as f:
    # raise Exception()
    time.sleep(2)
    print(f)

 

from functools import total_ordering
@total_ordering # inefficiency
class B:
    def __init__(self, p):
        self.p = p

    def __lt__(self, other): # choose one
        return self.p < other.p
    def __eq__(self,other): # required
        return self.p == other.p
b=B(5)
v=B(6)
print(b==v)
print(b!=v)
print(b>=v)
print(b<=v)

 

posted @ 2020-10-06 20:06  ascertain  阅读(152)  评论(0编辑  收藏  举报