zoukankan      html  css  js  c++  java
  • python笔记64

    前言

    with 语句适用于对资源进行访问的场景,在使用过程中如果发生异常需执行“清理”操作释放资源,比如常用的场景是with open打开文件操作。

    with 打开文件场景

    我们接触的第一个使用with的场景是用open函数对文件的读写操作,下面的代码是打开文件读取文件内容后用close关闭

    fp = open('1.txt', 'r')
    r = fp.read()
    print(r)
    fp.close()
    

    上面的代码会有2个弊端:
    1.如果在打开文件操作的过程中fp.read()出现异常,异常没处理
    2.很多同学没用使用fp.close()关闭的操作的习惯,导致资源一直不会释放
    所以推荐用下面这种with语法

    with open('1.txt', 'r') as fp:
        r = fp.read()
        print(r)
    

    学到这里我们都是死记硬背,只知道用with有这么2个好处,但不知道为什么这么用,也不知道其它的场景能不能用with?

    with 使用原理

    上下文管理协议(Context Management Protocol):包含方法 __enter__()__exit__(),支持该协议的对象要实现这两个方法。
    上下文管理器(Context Manager):
    支持上下文管理协议的对象,这种对象实现了__enter__()__exit__()方法。上下文管理器定义执行with语句时要建立的运行时上下文,负责执行with语句块上下文中的进入与退出操作。
    通常使用with语句调用上下文管理器,也可以通过直接调用其方法来使用。

    with语句需当一个新的语法去学习,使用语法格式

    with EXPR as Variable:
        BLOCK
    

    其中EXPR可以是任意表达式;as Variable是可选的,as的作用类似于=赋值。其一般的执行过程是这样的:

    • 执行EXPR,生成上下文管理器context_manager;
    • 获取上下文管理器的__exit()__方法,并保存起来用于之后的调用;
    • 调用上下文管理器的__enter__()方法;如果使用了as子句,则将__enter__()方法的返回值赋值给as子句中的Variable;
    • 执行 BLOCK 中的代码块;

    先看一个示例,使用with语法的时候,先调用__enter__方法,再执行 BLOCK 代码块,最后调用__exit__退出代码

    class WithDemo(object):
        def __init__(self):
            self.name = "yoyo"
    
        def start(self):
            print("start")
    
        def __enter__(self):
            print("enter---")
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print("quit 退出代码")
    
    with WithDemo() as a:
        print("11")
    

    运行结果

    enter---
    11
    quit 退出代码
    

    不管是否执行过程中是否发生了异常,执行上下文管理器的__exit__()方法,exit()方法负责执行“清理”工作,如释放资源等。
    如果执行过程中没有出现异常,或者语句体中执行了语句break/continue/return,则以None作为参数调用__exit__(None, None, None);
    如果执行过程中出现异常,则使用sys.exc_info得到的异常信息为参数调用__exit__(exc_type, exc_value, exc_traceback);
    出现异常时,如果__exit__(self, exc_type, exc_val, exc_tb)返回False,则会重新抛出异常,让with之外的语句逻辑来处理异常,这也是通用做法;

    # 作者-上海悠悠 QQ交流群:717225969 
    # blog地址 https://www.cnblogs.com/yoyoketang/
    
    
    class WithDemo(object):
        def __init__(self):
            self.name = "yoyo"
    
        def start(self):
            print("start")
            return self
    
        def __enter__(self):
            print("enter---")
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print("quit 退出代码")
            return False
    
    with WithDemo() as a:
        print("11")
        a.start("a")
    

    调用start方法出现异常,也会执行__exit__,此方法返回False,于是就会抛出异常

    enter---
    11
    quit 退出代码
    Traceback (most recent call last):
      File "D:/wangyiyun_hrun3/demo/c.py", line 18, in <module>
        a.start("a")
    AttributeError: 'NoneType' object has no attribute 'start'
    

    如果返回True,则忽略异常,不再对异常进行处理。

        def __exit__(self, exc_type, exc_val, exc_tb):
            print("quit 退出代码")
            return True
    

    返回True的时候,不会抛出异常

    allure.step使用场景

    在使用pytest+allure报告的时候,经常会看到在用例里面使用with allure.step方法

    # 作者-上海悠悠 QQ交流群:717225969 
    # blog地址 https://www.cnblogs.com/yoyoketang/
    
    
    import pytest
    import allure
    import requests
    
    
    @pytest.fixture(scope="session")
    def session():
        s = requests.session()
        yield s
        s.close()
    
    
    def test_sp(s):
        with allure.step("step1:登录"):
            s.post('/login', json={})
        with allure.step("step2:添加商品"):
            s.post('/goods', json={})
        with allure.step("step3:查询商品id"):
            s.get('/gooods/1')
        assert 1 == 1
    

    可以看下allure.step()方法的源码

    def step(title):
        if callable(title):
            return StepContext(title.__name__, {})(title)
        else:
            return StepContext(title, {})
    

    返回的是StepContext类的实例对象

    class StepContext:
    
        def __init__(self, title, params):
            self.title = title
            self.params = params
            self.uuid = uuid4()
    
        def __enter__(self):
            plugin_manager.hook.start_step(uuid=self.uuid, title=self.title, params=self.params)
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            plugin_manager.hook.stop_step(uuid=self.uuid, title=self.title, exc_type=exc_type, exc_val=exc_val,
                                          exc_tb=exc_tb)
    

    在StepContext类里面定义了__enter____exit__方法
    于是有同学就想当然是不是也可以allure.title(),这个是不对的。

    其它使用场景

    使用python的requests模块发请求

    # 作者-上海悠悠 QQ交流群:717225969 
    # blog地址 https://www.cnblogs.com/yoyoketang/
    
    
    import requests
    
    s = requests.Session()
    r = s.get("https://www.cnblogs.com/yoyoketang/")
    print(r.status_code)
    s.close()
    

    在Session类也可以看到定义了__enter____exit__方法

    class Session(SessionRedirectMixin):
        """A Requests session.
    
        Provides cookie persistence, connection-pooling, and configuration.
    
        Basic Usage::
    
          >>> import requests
          >>> s = requests.Session()
          >>> s.get('https://httpbin.org/get')
          <Response [200]>
    
        Or as a context manager::
    
          >>> with requests.Session() as s:
          ...     s.get('https://httpbin.org/get')
          <Response [200]>
        """
    
        __attrs__ = [
            'headers', 'cookies', 'auth', 'proxies', 'hooks', 'params', 'verify',
            'cert', 'adapters', 'stream', 'trust_env',
            'max_redirects',
        ]
    
        def __init__(self):
            ......
    
     
    
        def __enter__(self):
            return self
    
        def __exit__(self, *args):
            self.close()
    

    在源码里面是可以看到with语法的使用示例

          >>> with requests.Session() as s:
          ...     s.get('https://httpbin.org/get')
          <Response [200]>
    

    于是也可以这样写

    with requests.Session() as s:
        r = s.get("https://www.cnblogs.com/yoyoketang/")
        print(r.status_code)
    

    参考资料:https://www.cnblogs.com/pythonbao/p/11211347.html
    参考资料:https://blog.csdn.net/u012609509/article/details/72911564

  • 相关阅读:
    Cocos2d-x教程(34)-三维物体OBB碰撞检測算法
    POJ 2485 Highways 最小生成树 (Kruskal)
    LintCode-分糖果
    云存储市场布局已定,怎样助力企业互联网转型
    HDU 1853 Cyclic Tour(最小费用最大流)
    windows下基于bat的每1分钟执行一次一个程序
    python中匹配中文,解决不匹配,乱码等问题
    bytes,packet区别 字节数据包
    wmic
    paramiko 模块封装
  • 原文地址:https://www.cnblogs.com/yoyoketang/p/15169090.html
Copyright © 2011-2022 走看看