web-dev-qa-db-ja.com

オプションのモジュールをインポートしようとするときにImportErrorをキャッチしても安全ですか?

私は通常、このパターンをPython作業しているプロジェクトごとに少なくとも1回見ます。たとえば、Djangoプロジェクトでは、これはしばしば基本設定ファイル:

try:
  from .local_settings import *
except ImportError:
  pass

また:

try:
  import simplejson as json
except ImportError:
  import json

これはいつも私を少しだけ悩ませてきました。モジュールが正常にインポートされた後、ImportError自体がトリガーされた場合はどうなりますか?たとえば、最初の例では、local_settingsモジュールは存在しますが、次にlocal_settingsは存在しないモジュールをインポートしようとします。

これは、オプションのモジュールをインポートする最も安全な方法ですか、この機能を実現するためのより良い方法がありますか、それともコンテキスト/使用法に依存しますか?

10
user34530

一般的に、インポートするオプションの依存関係はそれ自体で機能することが想定されています。必要なtransitive依存関係が欠落しているために、欠落しているオプションの依存関係をインポートしようとしても、インポートできなくてもほとんど違いはありません。

言い換えると、プログラムがインストールされていない、またはsimplejsonの依存関係がインストールされていないために、プログラムがsimplejsonが使用できないことを気にする必要があるのはなぜですか?どちらの方法でもsimplejsonは使用できません。

オプションの依存関係の場合、推移的な依存関係を含め、依存関係が正しくインストールされていることを確認するのはパッケージインストーラーの役割です。

local_settingsのようなものについては、実際に推移的なImportErrorがマスクされる(小さな)リスクがあります。キャッチされたImportError例外は、いつでもレベルDEBUGなどでログに記録して、例外の原因を簡単に確認できます。

try:
    from .local_settings import *
except ImportError:
    log.debug('local_settings failed to import', exc_info=True)

loggingパッケージは、exc_infoをtrueに設定したときに後で検査できるように、ログに例外情報を含めます。

別のオプションは warnings module で警告を発行することです。標準ライブラリには ImportWarning class があります:

import warnings

try:
    from .local_settings import *
except ImportError:
    warnings.warn('local_settings failed to import', ImportWarning)
10
Martijn Pieters

これは、モジュールにインポート時の副作用がないことを前提として、一般的に安全です。

インポートされたモジュールがインポート時に例外(ImportErrorだけでなく)を発生させる場合、 それはsys.modules から削除されます。これは、他のコードがモジュールをインポートしようとした場合、部分的に初期化されたモジュールを取得しないことを意味します。代わりに、Pythonはモジュールをもう一度ロードしようとし、おそらくImportErrorで失敗します。

モジュールにインポート時の副作用がある場合、これらの効果は元に戻されないため、これにより問題が発生する可能性があります。特に、問題のあるモジュールが成功したが別のモジュールをインポートした場合、後者はsys.modulesから削除されません。この特定の副作用が問題になることはめったにありませんが、一部の副作用はより厄介な場合があります。

3
Kevin