故有此文

首发时间:2018-02-23 15:28


事先看来生龙活虎篇博客说博主python面试时遇会师试官提问with的原理,而这位博主的博文未有聊到with原理,故有此文。

 

 

关于with语句,官方文书档案中是如此描述的:

The with statement is used to wrap the execution of a block with
methods defined by a context manager (see section With Statement Context
Managers). This allows common tryexceptfinally usage
patterns to be encapsulated for convenient reuse.

with_stmt ::= “with” with_item (“,” with_item)* “:” suite

with_item ::= expression [“as” target]

The execution of the with statement with one “item” proceeds as follows:

The context expression (the expression given in the with_item) is
evaluated to obtain a context manager.

The context manager’s __exit__() is loaded for later use.

The context manager’s __enter__() method is invoked.

If a target was included in the with statement, the return value from
__enter__() is assigned to it.

Note
The with statement guarantees that if the __enter__() method returns
without an error, then __exit__() will always be called. Thus, if an
error occurs during the assignment to the target list, it will be
treated the same as an error occurring within the suite would be. See
step 6 below.

The suite is executed.

The context manager’s __exit__() method is invoked. If an exception
caused the suite to be exited, its type, value, and traceback are passed
as arguments to __exit__(). Otherwise, three None arguments are
supplied.

 

谷歌(Google卡塔 尔(阿拉伯语:قطر‎翻译成普通话便是:

with语句用于接受由上下文物管理理器定义的法子来封装块的实行(请参见使用语句上下文物管理理器大器晚成节卡塔尔国。
那允许通用的try…except…finally使用格局被封装以便于重用【那句话大致敬思正是“with语句”相通于try…except…finally封装之后的的事态】。

含有二个“项目”的with语句的试行进程如下:
1.上下文表达式(在with_item中付出的表明式卡塔尔国被评估以得到上下文物管理理器。【会有别于连串来拍卖,如文件,进度等都得以选拔with语句】
2.上下文物管理理器的__exit
__(卡塔 尔(阿拉伯语:قطر‎被加载供之后采用。【负担上下文的退出】
3.上下文物处理理器的__enter __(卡塔尔方法被调用。【肩负上下文的进去】
4.借使在with语句中含有指标,则将__enter
__(卡塔尔国的重临值分配给它。【假设with前边随着as 对象(如with open() as
f卡塔 尔(英语:State of Qatar),那么此指标拿到with上下文对象的__enter__()的重临值,(附:应该是相同操作数据库时的接连对象和游标的不相同卡塔 尔(英语:State of Qatar)】

注意
with语句保险,假如__enter
__(卡塔尔国方法重回时不曾错误,那么将始终调用__exit __(卡塔 尔(阿拉伯语:قطر‎。
由此,假使在分配给指标列表时期发生错误,它将被视为与套件内发出的荒谬相符。
请参阅下边的第6步。

5.该套件已进行。【意思就是语句体中的进程推行完成,实施完成就到第六步–调用__exit__()来退出】
6.上下文物管理理器的__exit __(卡塔 尔(阿拉伯语:قطر‎方法被调用。
借使那一个引致套件退出,则其连串,值和追忆作为参数字传送递给__exit
__(卡塔 尔(英语:State of Qatar)。 不然,将提供多少个无参数。

关于退出返回值:

If the suite was exited due to an exception, and the return value from the __exit__() method was false, the exception is reraised. If the return value was true, the exception is suppressed, and execution continues with the statement following the with statement.

If the suite was exited for any reason other than an exception, the return value from __exit__() is ignored, and execution proceeds at the normal location for the kind of exit that was taken.

中文:
如果套件由于异常而退出,并且__exit __()方法的返回值为false,则会重新对异常进行重新评估。 如果返回值为true,则异常被抑制,并继续执行with语句后面的语句。

如果套件由于除了异常之外的任何原因而退出,则__exit __()的返回值将被忽略,并且执行将在正常位置继续进行。

 

 

 

意思就是:

如果是异常退出,那么会返回false,(根据文档中的exit的描述“that __exit__() methods should not reraise the passed-in exception; this is the caller’s responsibility.”,大概意思就是exit()不会处理异常,会重新抛出异常抛出给外面,由调用者处理,因为这是调用者的责任)

 

如果返回 True,则忽略异常,不再对异常进行处理【(在exit内部处理完异常后,可以让”__exit__()”方法返回True,此时该异常就会不会再被抛出,with会认为它的执行体没有发生异常)】

 

 

(with会识别再次回到值,依据再次回到值来拍卖,假诺是False,那么with会将施行体中的十分抛出,倘使是True,那么with会以为未有发出至极(忽视万分卡塔尔,而继续实行外面包车型地铁话语,但出于内部调用的了__exit__(),所以在相当之后的说话是不会运转的卡塔尔

 

附上一个文书档案中提供的贰个有关with中运用锁的例证:

图片 1

 

多少个测试:

1.实行体中爆发分外:

import time
class myContextDemo(object):
    def __init__(self,gen):
        self.gen = gen
    def __enter__(self):
        print("enter in ")
        return self.gen
    def __exit__(self, exc_type, exc_val, exc_tb):
#exc_type是exception_type  exc_val是exception_value  exc_tb是exception_trackback
        print("exit in ")
        if exc_type is None:#如果是None 则继续执行
            print("None:",exc_type, exc_val, exc_tb)

        else: #异常不为空时执行,这一步,如果with语句体中发生异常,那么也会执行
            print("exception:", exc_type, exc_val, exc_tb)
            print("all done")



if __name__=="__main__":
    gen=(i for i in range(5,10))
    G=myContextDemo(gen)
    with G as f :
        print("hello")
        for i in f:
            print(i,end="t")
        #测试1:执行体中发生异常
        raise Exception("母鸡啊")
    print("main continue")

结果呈现:图片 2

1.抛出特别后,前面main continue不再实行

2.__exit__()中的else会执行

 

测量检验2:当else中威逼重返为True时:

 

import time
class myContextDemo(object):
    def __init__(self,gen):
        self.gen = gen
    def __enter__(self):
        print("enter in ")
        return self.gen
    def __exit__(self, exc_type, exc_val, exc_tb):
#exc_type是exception_type  exc_val是exception_value  exc_tb是exception_trackback
        print("exit in ")
        if exc_type is None:#如果是None 则继续执行
            print("None:",exc_type, exc_val, exc_tb)

        else: #异常不为空时执行,这一步,如果with语句体中发生异常,那么也会执行
            print("exception:", exc_type, exc_val, exc_tb)
            print("all done")
            return True #这里如果返回true可以看到发生异常后,main continue可以执行
            #即,如果exc_type是true,那么会继续执行,实际上,也可以在这里处理一下异常再返回true


if __name__=="__main__":
    gen=(i for i in range(5,10))
    G=myContextDemo(gen)
    with G as f :
        print("hello")
        for i in f:
            print(i,end="t")
        raise Exception("母鸡啊")
        # print("continue")#这里不会执行
    print("main continue")

结果呈现:图片 3

1.回去True之后,with会忽略非常,继续施行,所以那边“main continue”能试行

2.哪怕忽视相当,在with体中丰裕之后的口舌依然不会执行

附:理论上能够在回来True以前管理一下相当

 

 

 

 

 

 

 

PS:假使我们想要驾驭得更详尽,可以友善尝尝去读一下官方文书档案。

依赖关于with语句的详尽介绍官方文书档案:


相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website