5

我有以下项目层次结构:

project_dir
  lib
    __init__.py
    ...
    some_script.py
    ...
    agent
      __init__.py
      ...
      errors.py
      some_agent_script.py
      ...

lib/agent/erros.py 中有 SomeException 类定义,我使用以下代码将它们导入 lib/agent/some_agent_script.py 中:

from errors import SomeException

我也使用以下代码导入 lib/some_script.py

from agent.errors import SomeException

问题是当我在 lib/agent/some_agent_script.py 中引发 SomeException 时, lib/some_script.py 无法在 except 块中捕获它:

try:
    # Here comes a call to lib/agent/some_agent_script.py function
    # that raises SomeException
except SomeException, exc:
    # Never goes here
    print(exc)
except Exception, exc:
    print(exc.__class__.__name__) # prints "SomeException"

    # Let's print id's
    print(id(exc.__class__))
    print(id(SomeException))
    # They are different!

    # Let's print modules list
    pprint.pprint(sys.modules)

我可以在 sys.modules 中看到错误模块被导入了两次:第一次是使用“agent.errors”键,第二次是使用“lib.agent.errors”键

下面的代码是正确的,但它不是一个漂亮的解决方案:

agent_errors = sys.modules.get('agent.errors')
from agent_errors import SomeException

try:
    # Here comes a call to lib/agent/some_agent_script.py function
except SomeException:
    print('OK')

我应该怎么做才能使这个模块不导入两次?

4

1 回答 1

2

您应该始终使用完全限定的导入。

from lib.agent.errors import SomeException

在使用它的每个模块中执行此操作。然后它将始终具有相同的包名称。您可能还应该更改顶级包名称。“lib”这个名字太笼统了。

如果您碰巧将模块命名为与基本模块或“库存”模块相同的名称,这也将为您省去一些麻烦。例如,假设您创建了一个模块lib/agent/socket.py并在其中lib/agent/some_agent_script.py编写了import socket. 您实际上不会得到您的模块,而是库存模块。

因此,最好养成始终使用完全限定包名称的习惯,如果可以的话,不要使用公共根目录。

另一种方法是使用绝对导入。

from __future__ import absolute_import

import .errors

注意前导点。这从当前包中显式导入。它也应该可以解决您的问题,但我承认我没有尝试过。

于 2012-11-02T13:45:30.110 回答