美文网首页
记一次try finally中隐藏的坑

记一次try finally中隐藏的坑

作者: 逆小苍 | 来源:发表于2021-09-06 17:55 被阅读0次

最近在工作的时候,遇到了一个问题,源码简化后如下:

import os

def test():
    b = None
    e = None
    try:
        for _ in b:
            break
    except Exception as e:
        raise e
    finally:
        if e is not None:
            os._exit(0)


if __name__ == '__main__':
    test()

简单来说,就是遇到异常后,抛出,最后判断异常如果存在,就退出进程
执行后出现错误UnboundLocalError: local variable 'e' referenced before assignment
详情如下:

Traceback (most recent call last):
  File "a.py", line 11, in test
    raise e
  File "a.py", line 8, in test
    for _ in b:
TypeError: 'NoneType' object is not iterable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "a.py", line 18, in <module>
    test()
  File "a.py", line 13, in test
    if e is not None:
UnboundLocalError: local variable 'e' referenced before assignment

很奇怪,本来e已经在开始的时候定义了,为什么最后会说e未被定义就使用了呢?
于是打印出local()来看下实时的变量
ps:locals() 函数会以字典类型返回当前位置的全部局部变量。
代码如下:

import os

def test():
    b = None
    e = None
    try:
        for _ in b:
            break
    except Exception as e:
        print(locals())
        print("--------")
        raise e
    finally:
        print(locals())
        print("~~~~~~")
        if e is not None:
            os._exit(0)

if __name__ == '__main__':
    test()

结果如下:

{'e': TypeError("'NoneType' object is not iterable",), 'b': None}
--------
{'b': None}
~~~~~~
Traceback (most recent call last):
  File "a.py", line 13, in test
    raise e
  File "a.py", line 8, in test
    for _ in b:
TypeError: 'NoneType' object is not iterable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "a.py", line 22, in <module>
    test()
  File "a.py", line 17, in test
    if e is not None:
UnboundLocalError: local variable 'e' referenced before assignment

由此可以发现,在进入finall模块前,e变量已经被回收了,因此会出现UnboundLocalError: local variable 'e' referenced before assignment的报错

总结:
except 的异常 会在进入finally前进行回收
如果想完成最初的逻辑可以做出如下修改:

import os


def test():
    b = None
    exc = None
    try:
        for _ in b:
            break
    except Exception as e:
        exc = e
        raise e
    finally:
        if exc is not None:
            os._exit(0)


if __name__ == '__main__':
    test()

不要将异常名与变量名使用同一个,而是定义一个新的变量名,将异常复制给该变量即可

相关文章

网友评论

      本文标题:记一次try finally中隐藏的坑

      本文链接:https://www.haomeiwen.com/subject/peqywltx.html