防止'try'捕获异常并传递给python中的下一行 [英] Prevent 'try' to catch an exception and pass to the next line in python

查看:142
本文介绍了防止'try'捕获异常并传递给python中的下一行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个运行其他功能的python函数。

I have a python function that runs other functions.

def main():
    func1(a,b)
    func2(*args,*kwargs)
    func3()

现在我想对应用例外主要功能。如果main内部的任何函数都有异常,则该函数不应停止,而应继续执行下一行。换句话说,我想要以下功能

Now I want to apply exceptions on main function. If there was an exception in any of the functions inside main, the function should not stop but continue executing next line. In other words, I want the below functionality

def main():
    try:
        func1()
    except:
        pass
    try:
        func2()
    except:
        pass
    try:
        func3()
    except:
        pass

那么有什么方法可以循环遍历里面的每个语句 main 函数并在每行上应用例外。

So is there any way to loop through each statement inside main function and apply exceptions on each line.

for line in main_function:
    try:
        line
    except:
        pass

我只是不想在 main内部编写异常函数。

注意:如何防止尝试捕获python中的所有可能行?这个问题接近解决此问题,但是我不知道如何在a中循环遍历功能。

Note : How to prevent try catching every possible line in python? this question comes close to solving this problem, but I can't figure out how to loop through lines in a function.

如果您除了循环之外还有其他方法可以这样做,那也将有所帮助。

If you have any other way to do this other than looping, that would help too.

推荐答案

您想要的是某些语言中存在的选项,其中异常处理程序可以选择对下一个异常进行处理。这曾经导致不良代码,并且AFAIK从未在Python中实现。背后的基本原理是,您必须明确说明要如何处理异常以及要在哪里继续执行

What you want is on option that exists in some languages where an exception handler can choose to proceed on next exception. This used to lead to poor code and AFAIK has never been implemented in Python. The rationale behind is that you must explicitely say how you want to process an exception and where you want to continue.

在您的情况下,假设假设您有一个名为 main 的函数,该函数仅调用其他函数并且是自动生成的,我的建议是在生成和执行之间对其进行后期处理。检查模块甚至可以在运行时执行此操作:

In your case, assuming that you have a function called main that only calls other function and is generated automatically, my advice would be to post process it between its generation and its execution. The inspect module can even allow to do it at run time:

def filter_exc(func):
    src = inspect.getsource(func)
    lines = src.split('\n')
    out = lines[0] + "\n"
    for line in lines[1:]:
        m = re.match('(\s*)(.*)', line)
        lead, text = m.groups()
        # ignore comments and empty lines
        if not (text.startswith('#') or text.strip() == ""):
            out += lead + "try:\n"
            out += lead + "    " + text + "\n"
            out += lead + "except:\n" + lead + "    pass\n"
    return out

然后可以使用邪恶的 exec (仅来自的源中的输入您的函数):

You can then use the evil exec (the input in only the source from your function):

exec(filter_exc(main))  # replaces main with the filtered version
main()                  # will ignore exceptions






发表评论后,您想要一个更强大的溶胶可以处理多行语句和注释的语句。在这种情况下,您实际上需要解析并修改已解析的树。 ast 模块进行救援:


After your comment, you want a more robust solution that can cope with multi line statements and comments. In that case, you need to actually parse the source and modify the parsed tree. ast module to the rescue:

class ExceptFilter(ast.NodeTransformer):
    def visit_Expr(self, node):       
        self.generic_visit(node)
        if isinstance(node.value, ast.Call):  # filter all function calls
            # print(node.value.func.id)
            # use a dummy try block
            n = ast.parse("""try:
  f()
except:
  pass""").body[0]
            n.body[0] = node                  # make the try call the real function
            return n                          # and use it
        return node                           # keep other nodes unchanged

使用该示例代码:

def func1():
    print('foo')


def func2():
    raise Exception("Test")

def func3(x):
    print("f3", x)


def main():
    func1()
    # this is a comment
    a = 1
    if a == 1:  # this is a multi line statement
        func2() 
    func3("bar")

我们得到:

>>> node = ast.parse(inspect.getsource(main))
>>> exec(compile(ExceptFilter().visit(node), "", mode="exec"))
>>> main()
foo
f3 bar

在这种情况下,未解析的节点(*)写为:

In that case, the unparsed node(*) write as:

def main():
    try:
        func1()
    except:
        pass
    a = 1
    if (a == 1):
        try:
            func2()
        except:
            pass
    try:
        func3('bar')
    except:
        pass






或者,也可以包装每个顶级表达式:


Alternatively it is also possible to wrap every top level expression:

>>> node = ast.parse(inspect.getsource(main))
>>> for i in range(len(node.body[0].body)): # process top level expressions
    n = ast.parse("""try:
  f()
except:
  pass""").body[0]
    n.body[0] = node.body[0].body[i]
    node.body[0].body[i] = n

>>> exec(compile(node, "", mode="exec"))
>>> main()
foo
f3 bar

这里未解析的树写道:

def main():
    try:
        func1()
    except:
        pass
    try:
        a = 1
    except:
        pass
    try:
        if (a == 1):
            func2()
    except:
        pass
    try:
        func3('bar')
    except:
        pass






注意:如果使用 exec(compile(... 在函数中。默认情况下, exec(code) exec(code, globals(),locals())。在顶层,本地和全局词典是同一词典,因此顶层函数已被正确替换。但是,如果在函数中执行相同操作,则只能用只能从该函数调用的相同名称创建一个本地函数(当该函数返回时,它将超出范围) s locals()[’main’]()。因此,您必须通过显式传递全局字典来更改全局函数:


BEWARE: there is an interesting corner case if you use exec(compile(... in a function. By default exec(code) is exec(code, globals(), locals()). At top level, local and global dictionary is the same dictionary, so the top level function is correctly replaced. But if you do the same in a function, you only create a local function with the same name that can only be called from the function (it will go out of scope when the function will return) as locals()['main'](). So you must either alter the global function by passing explicitely the global dictionary:

exec(compile(ExceptFilter().visit(node), "", mode="exec"), globals(),  globals())

或返回修改后的函数而不更改原始函数:

or return the modified function without altering the original one:

def myfun():
    # print(main)
    node = ast.parse(inspect.getsource(main))
    exec(compile(ExceptFilter().visit(node), "", mode="exec"))
    # print(main, locals()['main'], globals()['main'])
    return locals()['main']

>>> m2 = myfun()
>>> m2()
foo
f3 bar






(*)Python 3.6在Tools / parser中包含一个未解析器,但是在pypi中存在一个更易于使用的版本


(*) Python 3.6 contains an unparser in Tools/parser, but a simpler to use version exists in pypi

这篇关于防止'try'捕获异常并传递给python中的下一行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆