【python】魔术方法2

举报
子都爱学习 发表于 2021/12/19 21:23:43 2021/12/19
【摘要】 上下文管理文件IO操作可以对文件对象使用上下文管理,使用with...as语法。with open('test', 'w') as f: pass我们仿照上例写一个自己的类,实现上下文管理class Point: passwith Point() as p: # AttributeError: __exit__ pass提示属性错误,没有 __exit__ ,看了需要这个属...

上下文管

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

with open('test', 'w') as f:
    pass

我们仿照上例写一个自己的类实现上下文管理

class Point:
    pass

with Point() as p: # AttributeError: __exit__
    pass

提示属性错误没有 __exit__ 看了需要这个属性,某些版本会显示没有 __enter__

QQ图片20211219210811.png

上下文管理对

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

__enter__

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

__exit__

退出与此对象相关的上下文

我们将类重新定义下,加入__enter__方法,和__exit__方法

import time

class Point:
    def __init__(self):
        print('init ~~~~~~~~')
        time.sleep(1)
        print('init over')

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

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit ============')

with Point() as p:
    print('in with-------------')

    time.sleep(2)
    print('with over')
    print('=======end==========')
    
# init ~~~~~~~~
# init over
# enter ~~~~~~~~
# in with-------------
# with over
# =======end==========
# exit ============

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


上下文管理的安全性

看看异常对上下文的影响

import time

class Point:
    def __init__(self):
        print('init ~~~~~~~~')
        time.sleep(1)
        print('init over')

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

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit ============')

with Point() as p:
    print('in with-------------')
    raise Exception('error')
    time.sleep(2)
    print('with over')
    print('=======end==========')

可以看出在抛出异常的情况下  with__exit__照样执行,  上下文管理是安全的。

with语句

# 3.py文件中写入下面代码
class Point:
    def __init__(self):
        print('init')
    def __enter__(self):
        print('enter')
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')

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

p = f = None
p = Point()
with p as f:
    print('in with-------------')
    print(p == f)    # False
    print('with over')
    print('=======end==========')

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

class Point:
    def __init__(self):
        print('init ~~~~~~~~')

    def __enter__(self):
        print('enter ~~~~~~~~')
        return self # 增加返回值

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit ============')

p = Point()
with p as f:
    print('in with-------------')
    print(p == f)       #  True
    print('with over')
    print('=======end==========')

 with语法,会调用with后的对象的__enter__方法,如果有as,则将该方法的返回值赋值给as子句的变量。上例,可以等价为 f = p.\__enter__()

上下文应用场

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

上下文应用

如何用支持上下文的类来对add函数计时

import time
import datetime

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

class Timeit:
    def __init__(self, fn):
        self.__fn = fn

    def __enter__(self):
        self.start = datetime.datetime.now()
        print('开始计时')
        return self

    def __call__(self, *args, **kwargs):
        return self.__fn(*args, **kwargs)

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

with Timeit(add) as t:
    print(add(4, 5))
    print(t(5, 6))

# 开始计时
# # 9
# # 11
# # add took 4.019243s.

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。