ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

魔术方法-上下文管理

2019-05-25 14:52:05  阅读:259  来源: 互联网

标签:__ exc self datetime 魔术 print 上下文 方法 def


魔术方法

上下文管理

文件IO操作可以对文件对象使用上下文管理,使用with…as语法
上下文管理对象

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

实例化对象的时候,并不会调用enter,进入with语句块调用__enter__方法,然后执行语句体,最后离开with语句块的时候,调用__exit__方法
with可以开启一个上下文运行环境,在执行前做一些准备工作,执行后做一些收尾工作
注意,with并不开启一个新的作用域
上下文管理的安全性

class Point:
    def __init__(self):
        print('init')
    
    def __enter__(self):
        print("enter")
    
    def __exit__(self,exc_type,exc_val,exc_tb):
        print('exit')
    
f = Point()
with f as p:
    import sys
    sys.exit(1)
    print(f==p)

从执行结果来看,依然执行__exit__函数,哪怕是退出python运行环境
说明上下文管理很安全

with语句

class Point:
    def __init__(self):
        print('init')
    
    def __enter__(self):
        print("enter")
    
    def __exit__(self,exc_type,exc_val,exc_tb):
        print('exit')
        #return 1 #压制异常

p = open('t1.py')
with p as f:
    print(f)
    print(p)
    print(f is p) #True
    print(f == p) #True

f = Point()
with f as p:
    
    print(f==p) #Flase

问题在__enter__方法上,它将自己的返回值赋给f,修改上例

with语法,会调用with后的对象__enter__方法,如果有as,则将该方法的返回值赋给as子句的变量
上例,可以等价为f = p.__enter__()
方法的参数
enter,没有其他参数
exit,方法有三个参数(self,exc_type,exc_val,exc_tb)
这三个参数都与异常有关
如果该上下文退出时没有异常,这三个参数都为None
如果有异常,参数意义如下
exc_type,异常类型
exc_val,异常的值
exc_tb(traceback),异常的追踪信息
__exit__方法返回一个等效True的值,则压制异常;否则,继续抛出异常

练习
为加法函数计时

  1. 使用装饰器显示该函数的执行时长
  2. 使用上下文管理来显示该函数的执行时长
import datetime
import time
from functools import wraps,update_wrapper
def lagger(fn):
    @wraps(fn)
    def warrapr(*args,**kwargs):
        statr = datetime.datetime.now()
        ret = fn(*args,**kwargs)
        datel = '{}s'.format((datetime.datetime.now()-statr).total_seconds())
        print(datel)
        return ret
    return warrapr


@lagger
def add(x,y):
    """12312"""
    time.sleep(2)
    return x+y
print(add(10,10))

class Point:
    """abddadss"""
    def __init__(self,fn):
        self.fn = fn
        update_wrapper(self,fn)
        # self.__name__ = fn.__name__
        # self.__doc__ = fn.__doc__

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

    def __exit__(self, exc_type, exc_val, exc_tb):
        delta = (datetime.datetime.now()-self.start).total_seconds()
        print('{}s'.format(delta))

with Point(add) as f:
    print(add(4,5))

用类当字符串

import datetime
import time
from functools import wraps,update_wrapper
class Point:
    """abddadss"""
    def __init__(self,fn):
        self.fn = fn
        update_wrapper(self,fn) #文档字符串
        # self.__name__ = fn.__name__  
        # self.__doc__ = fn.__doc__

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

    def __exit__(self, exc_type, exc_val, exc_tb):
        delta = (datetime.datetime.now()-self.start).total_seconds()
        # print(delta)
        # print(exc_tb)
        # print(exc_type)
        # print(exc_val)
        # print("~~~~~~~~~~~")

    def __call__(self, *args, **kwargs):
        statr = datetime.datetime.now()
        ret = self.fn(*args,**kwargs)
        datel = (datetime.datetime.now()-statr).total_seconds()
        print(datel)
        return ret

@Point
def add(x,y):
    """12312"""
    time.sleep(2)
    return x+y
print(add(10,10))

上面的类可以用在上下文管理,也可以用作字符串

上下文管理场景

1.增强功能
在代码执行的前后增加代码,以增强其功能.类似装饰器的功能
2.资源管理
打开了资源需要关闭,例如文件对象 网络连接 数据库连接等
3.权限验证
在执行代码之前,做权限的验证,在__enter__中处理

contextlib.contextmanager
它是一个装饰器实现上下文管理,装饰一个函数,而不用像类一样实现__enter__和__exit__方法
对下面的函数有要求:必须有yield,也就是这个函数必须返回一个生成器,且只有yield一个值
也就是说这个装饰器接收一个生成器对象作为参数

import contextlib

@contextlib.contextmanager
def foo():
    print('abc')
    try:
        yield
    finally:
        print('123')

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

f接收yield语句的返回值
增加异常
增加try finally
当yield发生处为生成器函数增加了上下文管理.这是为函数增加上下文机制的方式

  • 把yield之前的当做__enter__方法执行
  • 把yield之后的当做__exit__方法执行
  • 把yield的值为__enter__的返回值
    总结
    如果业务简单可以使用contextlib.contextmanager装饰器方式,如果业务复杂,用类的方式加__enter__和__exit__方法方便

标签:__,exc,self,datetime,魔术,print,上下文,方法,def
来源: https://blog.csdn.net/weixin_44800414/article/details/90546398

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有