私は 答えた 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.main
とpkg.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__.py
とstring.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 string
がalways絶対インポートが有効になっている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つのセクションの間のこの矛盾の解決は何ですか?
変更履歴はずさんに刻まれています。 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
の親ディレクトリがパス上にない場合は、それもパス上に固定する必要があります。
絶対インポートと相対インポートの違いは、パッケージからモジュールをインポートし、そのモジュールがそのパッケージから他のサブモジュールをインポートした場合にのみ発生します。違いを見ます:
$ 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
リストを変更するのを防ぎ、サブモジュールの意味を正しく処理します。
また、パッケージサブモジュールには明示的な相対インポートを使用することをお勧めします。これは、それらがより多くのセマンティクスと、失敗した場合のより良いエラーメッセージを提供するためです。