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 で、erros モジュールが 2 回インポートされていることがわかります。1 回目は「agent.errors」キーを使用し、2 回目は「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')

このモジュールを 2 回インポートしないようにするにはどうすればよいですか?

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 に答える