Pythonのimportに関しての個人的メモ。
間違っている点や他の躓きどころがあればコメント・PRをお願いします。
package内のimportにimplicit relative importは使えない
Python3以降の話。
例えば
$ tree .
.
└── mypackage
├── __init__.py
├── mymodule1.py
└── mymodule2.py
というディレクトリ構造のときに、mymodule2.pyからmymodule1.pyをimportしたい。
A = 1000
def show():
print('A: {}'.format(A))
import mymodule1
B = 100
def show():
print('A: {}, B: {}'.format(mymodule1.A, B))
のとき、
$ python2.7
Python 2.7.10 (default, Oct 23 2015, 19:19:21)
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import mypackage.mymodule2 as mymod2
>>> mymod2.show()
A: 1000, B: 100
$ python3
Python 3.5.2 (default, Aug 4 2016, 09:38:15)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import mypackage.mymodule2 as mymod2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/yusuke-nishioka/tests/tests1/mypackage/mymodule2.py", line 3, in <module>
import mymodule1
ImportError: No module named 'mymodule1'
のように、Python2.7ではmymodule2.pyからmymodule1.pyをimportできているが、
Python3.5ではimportできていないことがわかる。
原因
mymodule2.py内のimport mymodule1
は
同階層のmymodule1.pyをimportすることを意図している(これをimplicit relative importと呼ぶ)。
しかし、sys.path
に同名のpackageがあった場合、
mypackage/mymodule1.pyをimportしようとしているのか
sys.path上のmymoduleというpackageをimportしようとしているのか
区別ができないという問題がある。
そのため、Python3系ではimport xxx
はsys.path
に存在するpackageをimportするように変更され(absolute importと呼ぶ)、
implicit relative importは不可能になった。
解決策
package内のモジュールをimportするためには、
from . import mymodule1
のようにrelative importであることを明示しなければならない(これをexplict relative importと呼ぶ)。
参考URL
__package__
属性がNoneかつ__name__
属性が__main__
のとき、relative importは使えない
さて、上でpackage内のモジュールをimportするにはexplicit relavtive importを使うと述べたが、
package内のモジュールにも関わらずrelative importが使えない場合が存在する。
それはpackage内のモジュールの__package__
属性がNone
かつ__name__
属性が__main__
のときである。
$ tree .
.
└── mypackage
├── __init__.py
├── main.py
└── mymodule.py
A = 1000
def show():
print('A: {}'.format(A))
from . import mymodule
if __name__ == '__main__':
print('__package__: {}, __name__: {}'.format(
__package__, __name__))
mymodule.show()
のとき、main.pyを実行すると
$ python3 mypackage/main.py
Traceback (most recent call last):
File "mypackage/main.py", line 1, in <module>
from . import mymodule
ImportError: cannot import name 'mymodule'
と表示され、mypackage/mymodule.pyをimportできていないことが分かる。
原因
このとき、main.pyの__package
属性はNone、__name__
属性は__main__
となり、
top-levelのmoduleとして認識されている。
そのため、from .
の.
はmain.py自身となりmymodule
をimportできない。
解決策1
from . import mymodule
をfrom mymodule import show
とする。
解決策2
-m
オプションをつけて実行する。
$ python3 -m mypackage.main
__package__: mypackage, __name__: __main__
A: 1000
__package
属性はmypackage
、__name__
属性は__main__
となり
from .
の.
はmain.pyと同じ階層を指すことになり、
from . import mymodule
によってmymodule.pyをimportすることができる。
ちなみに、-m
によるmain.pyの実行はpackage外からおこなわれなければならない。
$ cd mypackage
$ python3 -m main
Traceback (most recent call last):
File "/Users/yusuke-nishioka/.anyenv/envs/pyenv/versions/3.6.1/lib/python3.6/runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "/Users/yusuke-nishioka/.anyenv/envs/pyenv/versions/3.6.1/lib/python3.6/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/Users/yusuke-nishioka/Documents/United/tmp/mypackage/main.py", line 1, in <module>
from . import mymodule
ImportError: attempted relative import with no known parent package
参考URL
__init__.py
がなくてもpackageをimportできる
Python3.3以降の話。
$ tree
.
├── mypackage1
│ ├── __init__.py
│ └── subdir1
│ ├── __init__.py.bak
│ └── mymodule1.py
└── mypackage2
└── subdir1
└── mymodule2.py
のとき、
$ python3
Python 3.5.2 (default, Aug 4 2016, 09:38:15)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import mypackage1
>>> import mypackage2
>>> dir(mypackage1)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
>>> dir(mypackage2)
['__doc__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
のように、__init__.py
がなくてもimportできている。
__init__.py
があるmypackage1
をregular package、
__init__.py
がないmypackage2
をnamespace packageと呼ぶ。
さらに、
>>> import sys
>>> sys.path.append('./mypackage1')
>>> sys.path.append('./mypackage2')
>>> import subdir1
>>> dir(subdir1)
['__doc__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
>>> subdir1.__path__
_NamespacePath(['./mypackage1/subdir1', './mypackage2/subdir1'])
として、違うパスだが同じ名前のディレクトリも同じnamespaceに属するpackageとして
_NamespacePathオブジェクトに格納されている。
importの順序
import xxx
が実行されると、
-
sys.path
にxxx/__init__.py
が存在する場合、regular packageとして取得できる -
sys.path
にxxx/__init__.py
は存在しないがxxx.{py,pyc,so}
が存在する場合、moduleとして取得できる -
sys.path
にxxx/__init__.py
もxxx.{py,pyc,so}
も存在しないが同名のディレクトリが存在する場合、namespace packageとして取得できる
regular packageとnamespace packageの違い
違いとして、
- namespace packageには
__file__
属性がない - regular packageの
__path__
はリストだが、namespace packageの__path__
は_NamespacePathオブジェクトである。
などがある。
さらに、namespace packageにする(__init__.py
をなくす)ことで、
>>> import subdir1.mymodule1
>>> import subdir1.mymodule2
>>> subdir1.mymodule1.__file__
'./mypackage1/subdir1/mymodule1.py'
>>> subdir1.mymodule2.__file__
'./mypackage2/subdir1/mymodule2.py'
のように、./mypackage1/subdir1
以下のmymodule1.py
と
./mypackage2/subdir1
以下のmymodule2.py
とを区別してimportできる。
まとめ
namespace packageを意図して使う場面は思いつかないが、
うっかり__init__.py
を忘れたとしてもmoduleとしてimportできる。
が、importの際に初期化処理を実行できる(__all__
を設定するなど)ことを考えると、
特に理由がない限り__init__.py
を置くのが良いと思われる。
詳しくはPEP 420 -- Implicit Namespace Packagesを参照。
参考URL
PEP 420 -- Implicit Namespace Packages
2012/07/24 Python 3.3b1 の名前空間パッケージを試してみた