上下文管理器

1.with语句

with语句实际上是一个非常通用的结构,允许我们使用上下文管理器。

2.什么是上下文管理器?

上下文管理器是一个对象,它支持两种方法:__enter__()和__exit__()。

如果想让一个对象可以使用with语句,必须实现实现它的__enter__()和__exit__()方法。

3.网络连接的例子

# -*- coding=utf-8 -*-
from socket import socket, AF_INET, SOCK_STREAM

class LazyConnection:
    def __init__(self, address, family=AF_INET, type=SOCK_STREAM):
        self.address = address
        self.family = family
        self.type = type
        self.sock = None

    def __enter__(self):
        if self.sock is not None:
            raise RuntimeError('网络已连接')
        self.sock = socket(self.family, self.type)
        self.sock.connect(self.address)
        return self.sock

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.sock.close()
        self.sock = None

LazyConnection类初始化并没有建立一个连接,连接的建立与销毁通过with语句来自动完成。

import pprint
if __name__ == "__main__":
    connect = LazyConnection(('www.httpbin.org', 80))
    with connect as s:
        s.send(b'GET /user-agent HTTP/1.1\r\n')
        s.send(b'host:www.httpbin.org\r\n')
        s.send(b'\r\n')
        response = s.recv(8196)
        response = str(response).replace('\\r\\n', '')
        pprint.pprint(response)

httpbin.org 这个网站能测试 HTTP 请求和响应的各种信息,比如 cookie、ip、headers 和登录验证等,且支持 GET、POST 等多种方法,对 web 开发和测试很有帮助。

有关httpbin具体信息可以查看其官网httpbin.org

我们这里模拟HTTP发送请求。

返回的响应:

输出重新排版,方便阅读:
(HTTP/1.1 200 OK
 Date: Fri, 08 May 2020 05:26:40 GMT
 Content-Type: "
 application/jsonContent-Length: 25
 Connection: keep-alive
 Server:'gunicorn/19.9.0'
 Access-Control-Allow-Origin: ''
 Access-Control-Allow-Credentials: true)

代码说明

我们的代码会被放到with语句块中执行。

当出现with语句的时候,调用对象的__enter__()方法会被调用,它返回的值(如果有)会被赋给as声明的变量。然后with语句块里面的代码开始执行。最后,__exit__()方法被触发进行清理工作。

不管with代码块中发生了什么(即使是异常),代码都会继续执行。

方法__enter__()不接受任何参数,在进入with语句时被调用,返回值被赋给关键字as后声明的变量。

方法_exit__()接受三个参数:异常类型(exc_type)、异常对象(exc_val)和异常跟踪(exc_tb)。在with语句块结束时被调用。

_exit__()方法可以自己决定如何利用这些异常信息,比如打印出来,或者对异常进行处理;

也可以选择忽略异常,返回None值,这样会抑制所有的异常;

如果返回True,那么异常会被清空,with语句块后面的程序会继续正常执行。

4.网络连接的改进版

上述的网络连接无法嵌套使用,即在with语句里继续嵌套使用with语句,无法建立多个连接。

下面是改进版:

# -*- coding=utf-8 -*-
from socket import socket, AF_INET, SOCK_STREAM


class LazyConnection:
    def __init__(self, address, family=AF_INET, type=SOCK_STREAM):
        self.address = address
        self.family = family
        self.type = type
        self.connections = []  # 建立一个连接列表

    def __enter__(self):
        sock = socket(self.family, self.type)
        sock.connect(self.address)
        self.connections.append(sock)  # 复制一个连接到栈里面
        return sock

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.connections.pop().close()  # 从栈中弹出最后一个连接并关闭它

5.应用场景

在需要管理一些资源比如文件、网络连接和锁的编程环境中,使用上下文管理器是很普遍的。 这些资源的一个主要特征是它们必须被手动的关闭或释放来确保程序的正确运行。
我们打开一个文件后,可能会忘记关掉它,但是with语句会解决这个问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值