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


89

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

コード全体で弾道的になり、完全なパッケージパスを指定せずに、同じパッケージ内のモジュールをインポートする場所を指摘しました。

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

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

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


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

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

そしてスポンジパッケージに私は書いています:

import icing

の代わりに

import cake.icing

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


すべてのPylintメッセージが同等に重要であるとは限らないことを理解しており、それらを却下することを恐れていませんが、そのような慣行が悪いアイデアと見なされる理由はわかりません。

私は誰かが落とし穴を説明できることを望んでいたので、この明らかに見せかけの警告をオフにするのではなく、コーディングスタイルを改善することができます(現在の予定です)。

回答:


98

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

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

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

from . import icing

2
特に妥協策のために+1。これはおそらく私が行くべき方法です。
奇数思考

2
import .icing代わりにできることにも注意してくださいfrom . import icing
ジャック

11
@Jackは実際にはできるとは思いません。PEP328のこの部分から:相対インポートは常に使用する必要がありますfrom <> importimport <>常に絶対です。もちろん、絶対インポートではfrom <> import、先頭のドットを省略して使用できます。その理由import .fooは、import XXX.YYY.ZZZそれ 以降XXX.YYY.ZZZは式で使用できるため です。ただし .moduleY、式では使用できません。
A.Wan

47

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

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

    想像してみて、あなたが持っているfoo.barfoo.bazbazあなたのパッケージにモジュールを。foo.barimports foo.baz、ただし相対的なインポートを使用します。

    さて、あなたがに移動foo.barしたbar場合、あなたのモジュールは突然異なるものをインポートしていますbaz

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

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

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

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


11
#2と#3の+1。ただし、#1は、ディレクトリ全体が移動した場合(レベルを押し下げた場合など)に対してオフセットする必要があります。
奇数思考
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.