__future__ importからabsolute_importは実際には何をしますか?


163

私がしている答えた私は、私が読んで理解に基づいて考えPythonで絶対的な輸入に関するご質問、Pythonの2.5変更履歴をとそれに付随するPEPを。ただし、Python 2.5をインストールしfrom __future__ import absolute_import、を適切に使用する例を作成しようとしたところ、状況がそれほど明確ではないことに気付きました。

上記のリンクされた変更ログから直接、このステートメントは、絶対的なインポートの変更に関する私の理解を正確に要約したものです。

次のようなパッケージディレクトリがあるとします。

pkg/
pkg/__init__.py
pkg/main.py
pkg/string.py

これはおよびサブモジュールpkgを含むという名前のパッケージを定義します。pkg.mainpkg.string

main.pyモジュールのコードを検討してください。ステートメントを実行するとどうなりimport stringますか?Python 2.4以前では、最初にパッケージのディレクトリを参照して相対インポートを実行し、pkg / string.pyを見つけて、そのファイルの内容をpkg.stringモジュールとしてインポートします。"string"そのpkg.mainモジュールは、モジュールの名前空間の名前にバインドされます。

だから私はこの正確なディレクトリ構造を作成しました:

$ ls -R
.:
pkg/

./pkg:
__init__.py  main.py  string.py

__init__.pystring.py空です。main.py次のコードが含まれています。

import string
print string.ascii_uppercase

予想通り、Python 2.5でこれを実行すると、AttributeError

$ python2.5 pkg/main.py
Traceback (most recent call last):
  File "pkg/main.py", line 2, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

ただし、2.5の変更ログにさらに沿って、次のことがわかります(強調が追加されています)。

Python 2.5ではimportfrom __future__ import absolute_importディレクティブを使用しての動作を絶対インポートに切り替えることができます。この絶対インポートの動作は、将来のバージョン(おそらくPython 2.7)でデフォルトになる予定です。絶対インポートがデフォルトにimport stringなると、は常に標準ライブラリのバージョンを見つけます。

このようにしてpkg/main2.py、と同じですmain.pyが、追加のfutureインポートディレクティブを作成しました。これは次のようになります。

from __future__ import absolute_import
import string
print string.ascii_uppercase

ただし、これをPython 2.5で実行すると、...で失敗しますAttributeError

$ python2.5 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 3, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

これはかなりきっぱりと声明と矛盾import stringします常に絶対的な輸入を有効にしてSTD-libのバージョンを確認します。さらに、絶対インポートが「新しいデフォルト」の動作になるようにスケジュールされているという警告にもかかわらず、私は__future__ディレクティブの有無にかかわらず、Python 2.7の両方を使用してこの同じ問題に遭遇しました。

$ python2.7 pkg/main.py
Traceback (most recent call last):
  File "pkg/main.py", line 2, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

$ python2.7 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 3, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

Python 3.5と同様に、またはなし(printステートメントが両方のファイルで変更されていると想定):

$ python3.5 pkg/main.py
Traceback (most recent call last):
  File "pkg/main.py", line 2, in <module>
    print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'

$ python3.5 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 3, in <module>
    print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'

これの他のバリエーションをテストしました。代わりのstring.py名前のディレクトリ- 、私は空のモジュールを作成しているstringだけで、空含んを__init__.py- 、代わりにからの輸入を発行するmain.py、私が持っているcd「とdはpkgとREPLから直接輸入を実行します。これらのバリエーション(またはそれらの組み合わせ)のいずれも、上記の結果を変更しませんでした。__future__ディレクティブと絶対インポートについて読んだ内容とは一致しません。

これは次のように簡単に説明できるようです(これはPython 2ドキュメントからのものですが、このステートメントはPython 3の同じドキュメントでも変更されていません)。

sys.path

(...)

プログラムの起動時に初期化されると、このリストの最初の項目はpath[0]、Pythonインタープリターを呼び出すために使用されたスクリプトを含むディレクトリです。スクリプトディレクトリが利用できない場合(たとえば、インタプリタがインタラクティブに呼び出される場合、またはスクリプトが標準入力から読み取られる場合)path[0]は、空の文字列で、Pythonに現在のディレクトリでモジュールを最初に検索するように指示します。

それで私は何が欠けていますか?どうして__future__ステートメントは言っているように見えないのですか?また、ドキュメントのこれら2つのセクション間、および説明された動作と実際の動作の間のこの矛盾の解決策は何ですか?


回答:


104

変更ログはだらしなく表現されています。 from __future__ import absolute_import何かが標準ライブラリの一部であるかどうかは気にせずimport string、絶対インポートがオンになっている標準ライブラリモジュールが常に提供されるとは限りません。

from __future__ import absolute_importつまり、の場合import string、Pythonはstringではなく、常に最上位モジュールを検索しますcurrent_package.string。ただし、Pythonがどのファイルを決定するために使用するロジックには影響しません。stringモジュール。あなたがするとき

python pkg/script.py

pkg/script.pyPythonのパッケージの一部のようには見えません。通常の手順に従って、pkgディレクトリがパスに追加さ.pyれ、pkgディレクトリ内のすべてのファイルはトップレベルのモジュールのように見えます。import string見つけpkg/string.py、それは相対的な輸入をやっているのではないが、ためpkg/string.pyが表示されますが、トップレベルのモジュールであることをstring。これが標準ライブラリstringモジュールではないという事実は出てきません。

ファイルをpkgパッケージの一部として実行するには、次のようにします

python -m pkg.script

この場合、pkgディレクトリはパスに追加されません。ただし、現在のディレクトリはパスに追加されます。

pkg/script.pyPython pkgがファイルとして実行されている場合でもパッケージの一部として扱うように、ボイラープレートを追加することもできます。

if __name__ == '__main__' and __package__ is None:
    __package__ = 'pkg'

ただし、これは影響しませんsys.pathpkgパスからディレクトリを削除するには、いくつかの追加の処理が必要です。また、pkg親ディレクトリがパス上にない場合は、それもパスに貼り付ける必要があります。


2
わかりました、つまり、わかりました。それがまさに私の投稿が文書化している行動です。しかし、それに直面して、2つの質問があります:(1.)「それが正確に真実ではない」場合、なぜドキュメントは断固としてそうだと言いますか?(2.)import stringでは、少なくともを通過することなく、誤って影を落とした場合はどうしますかsys.modules。これfrom __future__ import absolute_importは防止を意図したものではないですか?それは何をするためのものか?(PS、私は反対投票者ではありません。)
2ビットの錬金術師

14
ああ、それは私でした(「役に立たない」への反対票は「間​​違った」ではありませんでした)。下のセクションからOPがどのようにsys.path機能するかを理解していることは明らかであり、実際の質問はまったく扱われていません。つまり、実際には何をfrom __future__ import absolute_importするのでしょうか?
2015年

5
@ Two-BitAlchemist:1)変更ログはゆるい言葉であり、規範的ではありません。2)シャドウイングを停止します。独自の最上位モジュールを使用してシャドウイングした場合sys.modules、ライフルを通過しても標準ライブラリstringモジュールを取得できません。from __future__ import absolute_importトップレベルのモジュールがトップレベルのモジュールをシャドウイングするのを阻止するためのものではありません。これは、パッケージ内部モジュールがトップレベルのモジュールをシャドウイングするのを停止することになっています。ファイルをpkgパッケージの一部として実行すると、パッケージの内部ファイルがトップレベルとして表示されなくなります。
user2357112は、モニカ

@ Two-BitAlchemist:回答が修正されました。このバージョンはより役に立ちますか?
user2357112は、Monica

1
@storen:pkgは、インポート検索パス上のパッケージであると想定していますpython -m pkg.main-mファイルパスではなくモジュール名が必要です。
user2357112はモニカ

44

絶対インポートと相対インポートの違いが関係するのは、パッケージからモジュールをインポートし、そのモジュールがそのパッケージから他のサブモジュールをインポートする場合のみです。違いを見ます:

$ mkdir pkg
$ touch pkg/__init__.py
$ touch pkg/string.py
$ echo 'import string;print(string.ascii_uppercase)' > pkg/main1.py
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pkg/main1.py", line 1, in <module>
    import string;print(string.ascii_uppercase)
AttributeError: 'module' object has no attribute 'ascii_uppercase'
>>> 
$ echo 'from __future__ import absolute_import;import string;print(string.ascii_uppercase)' > pkg/main2.py
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>>> 

特に:

$ python2 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 1, in <module>
    from __future__ import absolute_import;import string;print(string.ascii_uppercase)
AttributeError: 'module' object has no attribute 'ascii_uppercase'
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>>> 
$ python2 -m pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ

python2 pkg/main2.py起動python2とインポートpkg.main2-mスイッチの使用と同じ)の動作が異なることに注意してください。

パッケージのサブモジュールを実行したい場合は、常に-mスイッチを使用してください。これにより、インタープリターがsys.pathリストをチェーンするのを防ぎ、サブモジュールのセマンティクスを正しく処理します。

また、パッケージサブモジュールには明示的な相対インポートを使用することを強くお勧めします。失敗した場合のセマンティクスとエラーメッセージが改善されるためです。


つまり、本質的には、「現在のディレクトリ」の問題を回避した狭い場合にのみ機能しますか?これは、PEP 328および2.5の変更ログで説明されているものよりもはるかに弱い実装のようです。ドキュメントが不正確だと思いますか?
2ビットの錬金術師

@ Two-BitAlchemist実際、あなたがやっていることは「狭いケース」です。実行するPythonファイルは1つだけですが、これにより何百ものインポートがトリガーされる場合があります。パッケージのサブモジュールは単に実行されるべきではありません、それだけです。
Bakuriu 2015年

python2 pkg/main2.pypython2を起動してからpkg.main2をインポートすると動作が異なるのはなぜ ですか?
2016

1
@storenこれは、相対インポートの動作が変更されたためです。pkg/main2.pypython(バージョン2)を起動すると、パッケージとして扱われませpkg。使用中python2 -m pkg.main2またはインポート中は、それがパッケージであることを考慮に入れてくださいpkg
バクリウ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.