11
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

attempted relative import beyond top-level packageと怒られたときに解決する方法

Posted at

はじめに

Pythonの相対importで今までよく考えずUnitTestで使っていたり,ディレクトリを掘ってわけることを怖がっていたのですが,そろそろ本腰を入れて解決しようと思いいたり,調べたのち解決できたので記録として残しておきます.

attempted relative import beyond top-level packageを再現しよう

以下のようなディレクトリ構成で

/package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
        moduleY.py
    subpackage2/
        __init__.py
        moduleZ.py
    moduleA.py

moduleZ.pymoduleX.py をimportしているとき,つまり moduleZ.py ファイル内で

from ..subpackage1 import moduleX

と書いて

$ pwd 
/package
$ cd subpackage2
$ python moduleZ.py
ValueError: attempted relative import beyond top-level package

## or
$ python subpackage2/moduleZ.py
ValueError: attempted relative import beyond top-level package

と無事再現できます.

解決するためには

ここの2つのリューション[1]がとても良い解決策を提示していたので使用しました.
今回は
moduleZ.py のimportを

from subpackage1 import moduleX

と書き換えて

$ pwd
/package
$ python -m subpackage2.moduleZ

で解決する方法をとります.
-m はライブラリモジュールとしてpythonスクリプトとして実行します.なので,/package をrootディレクトリ(__main__) としてsubpackage2/moduleZ.py を実行しているため,subpackage1/moduleX.py をimportして実行することができます.

Pythonのimportに対する考え方

PythonはPackageの考え方[2]はpython ~~~.pyを実行した場所をrootとして認識しroot以下に存在する~~~.pyをモジュール(~~~.py)として認識しています.このrootとして認識される~~~.pyスクリプトは1つだけです.さらに,python ~~~.pyとスクリプトを実行するとPythonの__main__がimportの特殊ケース[3]によってモジュール名が強制的に__main__となります.したがって,どのPythonスクリプトをroot(__main__)に実行しているのか実行ディレクトリの場所が大切になります.
今回の失敗例では以下のようにroot(__main__)はmoduleZ.pyの場所(今回はsubpackage2)となってしまいます.

$ pwd 
/package
$ cd subpackage2
$ python moduleZ.py
## or
python subpackage2/moduleZ.py

その結果,相対importで(subpackage1)をimportする際,root(subpackage2)の上(/pacakge)を参照しようとしてValueError: attempted relative import beyond top-level packageと怒られPythonスクリプトは実行できません.
ちなみにpythonで始まるREPLはカレントディレクトリが__main__となってるのでrootディレクトリで実行するとimportができます.
逆にどこかのパッケージ(ディレクトリ)内で実行してしてしまうとimportできない場合があります.

最後に

Pythonのimportはわかったようなわからないような不思議な感覚で使っていたので割と整理できて愛着がわきました.身近なものだとPythonのUnitTestでpython -mを使っている方は多いのではないでしょうか?調べ不足で私の誤認やタイプミスがありましたら,コメントに記載していただけると幸いです.また,この記事でPythonインポート正直理解できないと思われる方はぜひ参考資料も見ていただけると嬉しいです.

参考資料

[1] Relative imports for the billionth time
[2] Built-in Package Support in Python 1.5
[3] 5.8. main に対する特別な考慮

11
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?