web-dev-qa-db-ja.com

__future__ import absolute_importから実際に何をするのですか?

私は 答えた Pythonでの絶対インポートについての質問を持っています。これは Python 2.5 changelog とそれに付随する PEP を読んで理解したと思います。しかし、Python 2.5をインストールしてfrom __future__ import absolute_importを適切に使用する例を作成しようとすると、物事がそれほど明確ではないことがわかります。

上記リンクの変更履歴から直接、このステートメントはインポートの絶対的な変更に関する私の理解を正確に要約しました:

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

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

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

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では、from __future__ import absolute_importディレクティブを使用してimportの動作を絶対インポートに切り替えることができます。この絶対インポートの振る舞いは将来のバージョン(おそらくPython 2.7)ではデフォルトになるでしょう。絶対インポートがデフォルトになると、import stringは常に標準ライブラリのバージョンを検索します。

pkg/main2.pyと同じですが、将来のimportディレクティブを追加して、main.pyを作成しました。それは今このようになります:

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 stringalways絶対インポートが有効になっている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の代わりに、空のモジュール(空の__init__.pyのみを含むstringという名前のディレクトリ)を作成し、main.pyからインポートを発行する代わりに、cd'dからpkgにインポートし、REPLから直接インポートを実行します。これらのバリエーション(またはそれらの組み合わせ)のどちらも上記の結果を変更しませんでした。 __future__ディレクティブと絶対インポートについて読んだものとこれを調整することはできません。

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

sys.path

(...)

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

だから私は何が足りないのですか?どうして__future__ステートメントはそれが言うことをしないように見えますか、そして記述されたものと実際の振る舞いの間だけでなく、文書のこれらの2つのセクションの間のこの矛盾の解決は何ですか?

122

変更履歴はずさんに刻まれています。 from __future__ import absolute_importは、何かが標準ライブラリの一部であるかどうかを気にすることはなく、import stringは常に絶対インポートが有効な標準ライブラリモジュールを提供するわけではありません。

from __future__ import absolute_importは、あなたがimport stringであれば、Pythonは常にcurrent_package.stringではなく最上位のstringモジュールを探すことを意味します。しかし、これはPythonがstringモジュールであるファイルを決定するためにPythonが使用するロジックには影響しません。するとき

python pkg/script.py

pkg/script.pyはPythonのパッケージの一部のようには見えません。通常の手順に従って、pkgディレクトリがパスに追加され、pkgディレクトリ内のすべての.pyファイルは最上位モジュールのように見えます。 import stringは、相対インポートを行っているからではなく、pkg/string.pyが最上位モジュールstringであるように見えるため、pkg/string.pyを見つけます。これが標準ライブラリのstringモジュールではないという事実は出てきません。

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

python -m pkg.script

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

ファイルとして実行した場合でも、Pythonがpkgパッケージの一部として扱うように、pkg/script.pyに定型句を追加することもできます。

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

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

75
user2357112

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

$ 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リストを変更するのを防ぎ、サブモジュールの意味を正しく処理します。

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

36
Bakuriu