web-dev-qa-db-ja.com

Pythonの相対インポートの何が問題になっていますか?

私は最近、人気のあるPythonスタイルチェッカーである pylint のバージョンをアップグレードしました。

それは私のコード全体に弾道を行き渡り、完全なパッケージパスを指定せずに、同じパッケージでモジュールをインポートする場所を指摘しています。

新しいエラーメッセージはW0403です。

W0403:相対インポート%r、%rにする必要があります

パッケージディレクトリに関連するインポートが検出されたときに使用されます。


たとえば、私のパッケージが次のように構成されている場合:

/cake
  /__init__.py
  /icing.py
  /sponge.py
/drink

そして私が書くスポンジパッケージで:

import icing

の代わりに

import cake.icing

このエラーが発生します。


すべてのPylintメッセージが同等に重要であるとは限らず、それらを却下することを恐れないことは理解していますが、そのような慣行がなぜ不十分な考えと見なされるのかは理解できません。

私は誰かが落とし穴を説明できることを望んでいたので、(私が現在計画しているように)この一見誤った警告をオフにするのではなく、コーディングスタイルを改善できました。

92
Oddthinking

import icingの問題は、それが絶対インポートであるか相対インポートであるかがわからないことです。 icingは、Pythonのパスにあるモジュール、または現在のモジュールにあるパッケージである可能性があります。これは、ローカルパッケージがpython標準ライブラリパッケージと同じ名前である場合に、非常に煩わしくなります。

暗黙的な相対インポートを完全にオフにするfrom __future__ import absolute_importを実行できます。 PEP 328 には、あいまいさに関する正当化を含めて記述されています。 Python 3000では暗黙的な相対インポートが完全にオフになっていると思います。

相対インポートは引き続き可能ですが、次のように明示的に行う必要があります。

from . import icing
101
Winston Ewert

いくつかの理由があります。

  1. 相対インポートは、モジュールを移動すると簡単に壊れます。

    パッケージにfoo.barfoo.bazbazモジュールがあるとします。 foo.barfoo.bazをインポートしますが、相対インポートを使用します。

    ここで、foo.barbarに移動すると、モジュールが突然別のbazをインポートします。

  2. 相対インポートがあいまいです。上記の例でbarモジュールを移動しなくても、プロジェクトにやってくる新しい開発者は、ルートレベルではなくbazが実際にfoo.bazであることを認識しないことを許される可能性がありますbazパッケージ。

    絶対インポートにより、使用されているモジュールが明確になります。そしてimport thisが説くように、明示的は暗黙的よりも優れています。

  3. Python 3は暗黙的な相対インポートを完全に無効にしました。インポートは常に絶対として解釈されるようになりました。つまり、上記の例では、import bazは常に最上位モジュールをインポートします。代わりに明示的なインポート構文を使用する必要があります(from . import baz)。

    例をPython 2から3に移植すると、予期しない問題が発生します。絶対インポートを使用すると、コードの将来性が保証されます。

49
Martijn Pieters