Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在上下文管理器中捕获异常\uuuu输入_Python_Exception_Python 2.7_With Statement_Contextmanager - Fatal编程技术网

Python 在上下文管理器中捕获异常\uuuu输入

Python 在上下文管理器中捕获异常\uuuu输入,python,exception,python-2.7,with-statement,contextmanager,Python,Exception,Python 2.7,With Statement,Contextmanager,即使在\uuuu enter\uuuu()中存在异常,是否可以确保调用\uuuu exit\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu >>> class TstContx(object): ... def __enter__(self): ... raise Exception('Oops in __enter__') ... ... def __exit__(self

即使在
\uuuu enter\uuuu()
中存在异常,是否可以确保调用
\uuuu exit\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

>>> class TstContx(object):
...    def __enter__(self):
...        raise Exception('Oops in __enter__')
...
...    def __exit__(self, e_typ, e_val, trcbak):
...        print "This isn't running"
... 
>>> with TstContx():
...     pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __enter__
Exception: Oops in __enter__
>>> 

事后看来,上下文管理器可能不是最佳的设计决策。否。如果在
\uuuuu enter\uuuuuu()
中可能出现异常,则您需要自己捕获它,并调用包含清理代码的帮助器函数。

如下所示:

import sys

class Context(object):
    def __enter__(self):
        try:
            raise Exception("Oops in __enter__")
        except:
            # Swallow exception if __exit__ returns a True value
            if self.__exit__(*sys.exc_info()):
                pass
            else:
                raise


    def __exit__(self, e_typ, e_val, trcbak):
        print "Now it's running"


with Context():
    pass
要让程序在不执行上下文块的情况下继续运行,您需要检查上下文块内的上下文对象,并且只有在
\uuuuuu enter\uuuu
成功时才执行重要的操作

class Context(object):
    def __init__(self):
        self.enter_ok = True

    def __enter__(self):
        try:
            raise Exception("Oops in __enter__")
        except:
            if self.__exit__(*sys.exc_info()):
                self.enter_ok = False
            else:
                raise
        return self

    def __exit__(self, e_typ, e_val, trcbak):
        print "Now this runs twice"
        return True


with Context() as c:
    if c.enter_ok:
        print "Only runs if enter succeeded"

print "Execution continues"

据我所知,你不能完全跳过这个块。请注意,此上下文现在包含其中的所有异常。如果您不希望在
\uuuuuuuuuuuuuuuuuuu
成功时吞下异常,请检查
self。在
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu退出
中输入\uuuuuuuuuuuuuuu ok
返回False
如果
为True
则可以使用
context

或者举一个例子:


参见Python上的contextlib2如果不需要继承或复杂的子例程,可以使用较短的方法:

from contextlib import contextmanager

@contextmanager
def test_cm():
    try:
        # dangerous code
        yield  
    except Exception, err
        pass # do something
我是这样做的。它以错误作为参数调用_exit__()。如果args[0]包含错误,它将在执行清理代码后重新运行异常。

我建议您遵循RAII(资源获取是初始化)并使用上下文的构造函数来执行可能失败的分配。然后您的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
可以简单地返回self。如果构造函数失败,则在进入with上下文之前可能会引发异常

Foo类:
定义初始化(自):
打印(“初始化”)
引发异常(“booh”)
定义输入(自我):
打印(“输入”)
回归自我
定义退出(自身、exc类型、exc val、exc tb):
打印(“退出”)
返回错误
使用Foo()作为f:
打印(“带内”)
输出:

init
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  ...
    raise Exception("booh")
Exception: booh
init
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
...
引发异常(“booh”)
例外:嘘
包含一个用于确保清理的示例:

如的文档中所述,如果实现中的后续步骤失败,此方法可用于清理已分配的资源

因此,您可以使用
ExitStack()
作为
TstContx()
上下文管理器的包装上下文管理器:

从contextlib导入ExitStack
使用ExitStack()作为堆栈:
ctx=TstContx()
stack.push(ctx)#现在离开'stack'可以确保调用'ctx.\uuuuu exit.\uuuuuuu'。
使用ctx:
stack.pop_all()#因为'ctx.\uu enter.\uuuu'没有提升,所以它可以自行处理清理。
...  # 下面是实际上下文管理器的主体。

如果在
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu>中出现异常,您调用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu退出
,有没有办法在客户端代码中突破
块?哈哈,我只是同时考虑了一下。我用同样的逻辑更新了我的问题。如果目标是执行退出,而不是执行包含内容的异常,那么您是否只需执行
self.\uu exit\uu(*sys.exc\u info())
,然后
raise
原始异常,而不考虑退出返回值?我遗漏了什么吗?是的,但这会在contextlib中抛出“生成器未屈服”。@thg435,合理,但我们可以尝试包装“屈服”。。。最后,finally在finally块中有很多变通方法,但问题的根源是不可能用
块跳过整个
。因此,即使我们设法以某种方式在
enter
中处理异常,块仍然会运行,以
None
或一些其他垃圾作为参数。问题是,不可能从
\uuuu enter\uuu
中跳过
(请参见)+1:这个答案最适合我的用例,而且非常有意义。令人惊讶的是,它没有更多的选票。谢谢。从技术上讲,我没有回答这个问题;-)
stack = ExitStack()
try:
    x = stack.enter_context(cm)
except Exception:
    # handle __enter__ exception
else:
    with stack:
        # Handle normal case
from contextlib import contextmanager

@contextmanager
def test_cm():
    try:
        # dangerous code
        yield  
    except Exception, err
        pass # do something
class MyContext:
    def __enter__(self):
        try:
            pass
            # exception-raising code
        except Exception as e:
            self.__exit__(e)

    def __exit__(self, *args):
        # clean up code ...
        if args[0]:
            raise
init
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  ...
    raise Exception("booh")
Exception: booh