[Python] importの躓きどころ

More than 1 year has passed since last update.

Pythonのimportに関しての個人的メモ。

間違っている点や他の躓きどころがあればコメント・PRをお願いします。


package内のimportにimplicit relative importは使えない

Python3以降の話。

例えば

$ tree .

.
└── mypackage
├── __init__.py
├── mymodule1.py
└── mymodule2.py

というディレクトリ構造のときに、mymodule2.pyからmymodule1.pyをimportしたい。


./mypackage/mymodule1.py

A = 1000

def show():
print('A: {}'.format(A))



./mypackage/mymodule2.py

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 xxxsys.pathに存在するpackageをimportするように変更され(absolute importと呼ぶ)、

implicit relative importは不可能になった。


解決策

package内のモジュールをimportするためには、

from . import mymodule1のようにrelative importであることを明示しなければならない(これをexplict relative importと呼ぶ)。


参考URL

https://www.python.org/dev/peps/pep-0328/#rationale-for-relative-imports


__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


mypackge/mymodule.py

A = 1000

def show():
print('A: {}'.format(A))



mypackage/main.py

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 mymodulefrom 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

https://www.python.org/dev/peps/pep-0328/#relative-imports-and-name


__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.pathxxx/__init__.pyが存在する場合、regular packageとして取得できる


  • sys.pathxxx/__init__.pyは存在しないがxxx.{py,pyc,so}が存在する場合、moduleとして取得できる


  • sys.pathxxx/__init__.pyxxx.{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 の名前空間パッケージを試してみた