3

考虑以下两个模块 prog.py 和 err.py。这两个都是一个更大的程序的例子,它表现出这个问题。我需要将功能分离成更小的源文件,每个文件都有一个测试台。

Err.py 包括一个测试台。当它创建一个 prog 对象时,取决于异常被调用的方式,异常是否被捕获。

似乎即使 prog.py 在“from err import *”语句中导入 err 对象,模块名称仍然被推断(错误?),但似乎它所指的 err 与模块本身不同

这是 Python 2.7 中的错误还是预期行为?

只需获取两个文件并运行 err.py 即可了解我的意思..

第一个文件:

#prog.py

from err import *



class prog(object):
    def func1(self):
        raise MySubError

    def func2(self):
        doError()

第二个文件:

#err.py
import prog
import inspect
import sys

class myError(Exception):
    pass

class MySubError(myError):
    pass

def doError():
    raise MySubError

if __name__=="__main__":

    p=prog.prog()


    try:
        doError()
    except MySubError as er:
        print type(er)
        print "Captured 1"
    except Exception as er:
        print type(er)
        print "Not Captured 1"        

    try:
        p.func1()
    except MySubError as er:
        print type(er)
        print "Captured 2"
    except Exception as er:
        print type(er)
        print "Not captured 2"


    try:
        p.func2()
    except MySubError as er:
        print type(er)
        print "Captured 3"
    except Exception as er:
        print type(er)
        print "Not captured 3"

在我看来,好像 err 应该知道它是什么模块,并且异常应该是 err.MySubError,而不仅仅是 MySubError。我可以获取模块,但不能获取实例.....

输出:

<class '__main__.MySubError'>
Captured 1
<class 'test.MySubError'>
Not captured 2
<class 'test.MySubError'>
Not captured 3
4

2 回答 2

2

这里的问题是它err实际上充当了两个不同的模块,本质上。

在 Python 中运行的主模块称为__main__. 执行的所有内容都放入它的命名空间。这里发生的事情是您将模块导入到您的其他脚本中并且它被称为err,因此它们不被认为是相同的。

这有点奇怪,但有必要保持 Python 导入系统的工作方式一致。这里最好的答案是将您的异常移到您的脚本之外,称为__main__. 无论如何,这是一个很好的设计,因为您实际上是在此处创建循环导入。

于 2012-04-29T15:04:22.773 回答
1

问题是 python 不知道err.py与您的主脚本相同。通常一个模块只导入一次,但是当主脚本将自己作为一个模块导入时,python 会感到困惑,你实际上是在加载err.py两次。(我不知道有什么好的理由;也许@Latty 可以更具体)。

您可以通过这个简单的脚本看到问题:

# File: recur.py
import recur
print "This is the module"

if __name__ == '__main__':
    print "This is main"

如果你运行它,你不会得到无限递归,因为模块只被导入一次。但是您会看到两次“这是模块”。

只要您的主脚本不导入自身(直接或间接),将异常从一个模块导入另一个模块就没有问题。有两个相互依赖的模块 A 和 B 也没有问题,每个模块都导入另一个:尝试一下import A,您会发现它们中的每一个都只加载一次。

编辑:虽然我真的认为您应该避免将主脚本作为模块导入,但我只是为您的示例想到了一个修复:

# err.py
...
if __name__=="__main__":
    from prog.err import *     # add this line

这将用它们的模块版本替换所有重复的脚本类,并且一切都将按预期工作。

于 2012-04-29T15:25:57.567 回答