异常被执行了两次,并被不同的异常块捕获。

6

I have the following code:

file1.py

from file2 import tfun

class TestException(Exception):
    pass

try:
    print 'I am running'
    tfun()
except TestException as e:
    print 'I am caught'
    print type(e)
except Exception as e:
    print 'I am generally caught'
    print type(e)

file2.py

def tfun():
    from file1 import TestException
    raise TestException()

执行python file1.py的输出如下:

I am running
I am running
I am caught
<class 'file1.TestException'>
I am generally caught
<class 'file1.TestException'>

首先,为什么在这种情况下代码会执行两次?我可以理解导入是递归的,但为什么脚本的代码会再次执行?
其次,第二次即使与第一次相同类型也无法被相同的except块捕获,对此我也找不到解释。
最后,我正在尝试找到解决此问题的方法,而不需要将任何内容移动到新文件中,但似乎没有。有可能克服这个问题吗?
编辑:
对于第二个问题,我意识到这是因为代码位于模块级别。

3
+1 一个简短、完整的独立程序,演示手头的问题。参考:http://stackoverflow.com/help/mcve 和 http://SSCCE.org - Robᵩ
1个回答

7
如果您将一个模块作为脚本运行(即将其名称提供给解释器,而不是导入它),则它将在模块名称__main__下加载。
如果您随后从程序中导入相同的模块,则会重新加载并在其真实名称下重新执行。 如果您不小心,可能会重复执行某些操作。 http://effbot.org/zone/import-confusion.htm 您正在以两个不同的模块加载file1.py,第一次是通过命令行加载的。
python file1.py

在这种情况下,file1.py被加载为主模块__main__
第二次加载是由于您的导入语句引起的。
from file1 import TestException

在这种情况下,file1.py作为模块file1被加载。
因为file1.py作为两个不同的模块被加载,所以其中的每个东西都有两个不同的副本。特别是__main__.TestExceptionfile1.TestException不同。
因此,在__main__内部,该行代码:
except TestException as e:

即使在 tfun() 抛出 __file1__.TestException 的情况下,仍然捕获了 __main__.TestException。在 file1 中,相同的行捕获了 file1.TestException

在前一种情况下,类型不匹配,except: 子句不会运行;在后一种情况下,类型匹配,except: 子句将被执行。

也许这个程序可以更清楚地说明正在发生什么:

from file2 import tfun

class TestException(Exception):
    pass

try:
    print 'I am calling file2.tfun from', __name__
    tfun()
    print 'I have called file2.tfun from', __name__
except TestException as e:
    print 'I am caught in %s'%(__name__)
    print type(e), TestException
except Exception as e:
    print 'I am generally caught in %s'%__name__
    print type(e), TestException
print 'I am exiting from',__name__

结果:

$ python file1.py 
I am calling file2.tfun from __main__
I am calling file2.tfun from file1
I am caught in file1
<class 'file1.TestException'> <class 'file1.TestException'>
I am exiting from file1
I am generally caught in __main__
<class 'file1.TestException'> <class '__main__.TestException'>
I am exiting from __main__

一个简单的解决方法是修改file2.py:
def tfun():
    from __main__ import TestException
    raise TestException()

结果:

$ python file1.py 
I am calling file2.tfun from __main__
I am caught in __main__
<class '__main__.TestException'> <class '__main__.TestException'>
I am exiting from __main__

2
__main__.TestExceptionfile1.TestException 之间的区别是最棘手的部分,我认为。 - chepner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接