你所需要的,不仅仅是一个好用的代理。
原文出处: 人间世
计算机上下文(Context)对于我而言,一直是一个很抽象的名词.就像形而上学一样,经常听见有人说,但是无法和现实认知世界相结合.
最直观的上下文,莫过于小学的语文课,经常会问联系上下文,推测...,回答...,表明作者....文章里的上下文比较好懂,无非就是前与后.直到了解了计算机的执行状态,程式的运行,才稍微对计算机的上下文(context)有了一定的认识,多半还是只可意会,不可言传.而本文所讨论的上下文,简而言之,就是程式所执行的环境状态,或者说程式运行的情景.关于上下文的定义,我就不在多言,具体通过程式来理解.既然提及上下文,就不可避免的涉及Python中关于上下文的魔法,即上下文管理器(contextor).
上下文管理器的常用于一些资源的操作,需要在资源的获取与释放相关的操作,一个典型的例子就是数据库的连接,查询,关闭处理.先看如下一个例子:
上述的代码很简单,针对Database这个数据库类,提供了connect query 和close 三种常见的db交互接口.客户端的代码中,需要查询数据库并处理查询结果.当然这个操作之前,需要连接数据库(db.connect())和操作之后关闭数据库连接( db.close()).上述的代码可以work,可是如果很多地方有类似handle_query的逻辑,连接和关闭这样的代码就得copy很多遍,显然不是一个优雅的设计.
对于这样的场景,在python黑魔法—装饰器中有讨论如何优雅的处理.下面使用装饰器进行改写如下:
编写一个dbconn的装饰器,然后在针对handle_query进行装饰即可.使用装饰器,复用了很多数据库连接和释放的代码逻辑,看起来不错.装饰器解放了生产力.可是,每个装饰器都需要事先定义一下db的资源句柄,看起来略丑,不够优雅.
Python提供了With语句语法,来构建对资源创建与释放的语法糖.给Database添加两个魔法方法:
然后修改handle_query函数如下:
在Database类实例的时候,使用with语句.一切正常work.比起装饰器的版本,虽然多写了一些字符,但是代码可读性变强了.
前面初略的提及了上下文,那什么又是上下文管理器呢?与python黑魔法—迭代器类似,实现了迭代协议的函数/对象即为迭代器.实现了上下文协议的函数/对象即为上下文管理器.
迭代器协议是实现了__iter__方法.上下文管理协议则是__enter__和__exit__.对于如下代码结构:
Contextor 实现了__enter__和__exit__这两个上下文管理器协议,当Contextor调用/实例化的时候,则创建了上下文管理器contextor.类似于实现迭代器协议类调用生成迭代器一样.配合with语句使用的时候,上下文管理器会自动调用__enter__方法,然后进入运行时上下文环境,如果有as 从句,返回自身或另一个与运行时上下文相关的对象,值赋值给var.当with_body执行完毕退出with语句块或者with_body代码块出现异常,则会自动执行__exit__方法,并且会把对于的异常参数传递进来.如果__exit__函数返回True.则with语句代码块不会显示的抛出异常,终止程序,如果返回None或者False,异常会被主动raise,并终止程序.
大致对with语句的执行原理总结Python上下文管理器与with语句:
了解了with语句和上下文管理协议,或许对上下文有了一个更清晰的认识.即代码或函数执行的时候,调用函数时候有一个环境,在不同的环境调用,有时候效果就不一样,这些不同的环境就是上下文.例如数据库连接之后创建了一个数据库交互的上下文,进入这个上下文,就能使用连接进行查询,执行完毕关闭连接退出交互环境.创建连接和释放连接都需要有一个共同的调用环境.不同的上下文,通常见于异步的代码中.