python的魔术方法之上下文管理

上下文管理

  • 当一个对象同时实现了__enter__()和__exit__()方法,它就属于上下文管理的对象
方法意义
__enter __进入与此对象相关的上下文。如果存在该方法,with语法会把该方法的返回值作为绑定到as子句中指定的变量上
__exit __退出与此对象相关的上下文。
import time

class Point:
    def __init__(self):
        print("1:init----------")
        time.sleep(1)
        print('init over')
    
    def __enter__(self):
        print('2,enter ~~~~~~~~')
        return 1                  # as 后面的标识符拿到的就是__enter__的返回值
        
    def __exit__(self,exc_type,exc_val,exc_tb):
        print('exit')
        
f = Point()                       # 实例化f的时候,并不进入__enter__
with Point() as p:
    print('3   -----------')
----------------------------------------
1:init----------
init over
1:init----------
init over
2,enter ~~~~~~~~
3   -----------
exit
  • 实例化对象的时候,并不会调用enter,进入with语句块调用__enter__方法,然后执行语句体,最后离开with语句块的时候,调用__exit__方法
  • with 后面的对象必须有__enter__()方法和__exit__()方法,as后面的标识符拿到的是__enter__的返回值(with语法,会调用with后的对象的__enter__方法,如果有as,则将该方法的返回值赋给as子句的变量。)
  • 异常需要在with语句块中处理,
    在exit方法中有return,返回值等效bool值,等效False,将会把异常向外抛出,
    等效True,异常被压制,不向外抛出

方法的参数

  • __enter__方法没有其他参数。

  • __exit__方法有3个参数: __exit __(self, exc_type, exc_value, traceback) 这三个参数都与异常有关。如果该上下文退出时没有异常,这3个参数都为None。如果有异常,参数意义如下

    • exc_type,异常类型
    • exc_value,异常的值
    • traceback,异常的追踪信息
  • __exit__方法返回一个等效True的值,则压制异常;否则,继续抛出异常 如下

class Point:
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        print(1,self)
        
    def __enter__(self):
        print('2 ------------')
        return 1
    
    def __exit__(sefl,exc_type, exc_val, exc_tb):
        print(3,exc_type)
        print(4,exc_val)
        print(5,exc_tb)
        return 1
    def __str__(self):
        return str((self.x,self.y))

with Point(2,3) as p:
    a = 1/0           # 此处除0异常,本应该抛异常,但是__exit__()方法中有return值,且等效为True,所以异常被压制,因为异常,所以'pass'并不能打印
    print(6,'pass')
------------------------------------------
1 (2, 3)
2 ------------
3 <class 'ZeroDivisionError'>
4 division by zero
5 <traceback object at 0x00000214DE0E7408>

实现类做装饰器和上下文管理增强功能

下面的类即可以用在上下文管理,又可以用做装饰器

import time
import datetime

class Timed:
    """this is decoration"""
    def __init__(self, fn):
        self.fn = fn
        self.__doc__ = fn.__doc__      #实例属性更改应该在初始化配置的时候更改
        self.__name__ = fn.__name__

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

    def __exit__(self, exc_type, exc_val, exc_tb):
        delta = (datetime.datetime.now() - self.start).total_seconds()
        print("{} took {}s. context".format(self.fn.__name__, delta))

    def __call__(self, *args, **kwargs):     #实例功能的增加在函数调用的位置增加
        start = datetime.datetime.now()
        ret = self.fn(*args, **kwargs)
        delta = (datetime.datetime.now() - start).total_seconds()
        print(delta)
        return ret

@Timed  # add = Timed(add)
def add(x, y):
    '''this is add function'''
    time.sleep(1)
    v = x + y
    print(v)
    return x + y

add(3, 6)
print(add.__doc__,";",add.__name__)
----------------------------------------------------------------
9
1.000373
this is add function ; add
  • 上下文应用场景
    • 增强功能在代码执行的前后增加代码,以增强其功能。类似装饰器的功能。
    • 资源管理打开了资源需要关闭,例如文件对象、网络连接、数据库连接等
    • 权限验证在执行代码之前,做权限的验证,在__enter__中处理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值