ImportError: cannot import nameにいじめられた話
前書き
ImportErrorの中で、頻出し、即座に解消出来るのはこのようなものかと思う。
>>> import hoge Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: No module named 'hoge'
おおかたモジュール名を間違えたか、階層が異なるかのいずれかだろう。
しかし、今回私が遭遇したのは次のようなエラーだった。
>>> import sys >>> sys.path.append('hoge/') >>> from fuga import piyo Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: cannot import name 'piyo'
私はミスタイプもしていないし、何度確認しても階層hoge/fuga/piyoであった。
いったいなぜエラーが出たのか?どのようにして解決できるのか?
(熟練したPythonistaにとってはどっちもつまらないエラーかもしれないが)
具体的なコードと不可解な解決
「多分一般的なエラーだよ」と言いたいがために、hogeとかを使ってみた。
...が。もし一般的じゃなかったら恥ずかしいので、実際のコードを貼っておく。
>>> import sys >>> sys.path.append('C:/[中略]/TensorFlow/models/') >>> from object_detection.protos import hyperparams_pb2 Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: cannot import name 'hyperparams_pb2'
こんなコードだ。また、次のように書いたらエラーは解消された。
>>> import sys >>> sys.path.append('C:/[中略]/TensorFlow/') >>> from models.object_detection.protos import hyperparams_pb2
ダメ元で試してみたのに成功してしまったパターンの典型例である。
しかし、「よくわからんが解決」というのが一番気に食わないので粘った*1。
根本的原因 (推測だけど)
piyo.__path__を使えば、importしたパッケージpiyoのパスを知ることが出来る。
これを用いて、パッケージが本当はどこにあるのか調査してみよう。
# 上手くいくとき >>> import sys >>> sys.path.append('C:/[中略]/TensorFlow/') >>> from models import object_detection >>> object_detection.__path__ ['C:/[中略]\\models\\object_detection]
# 上手くいかないとき >>> import sys >>> sys.path.append('C:/[中略]/TensorFlow/models/') >>> import object_detection >>> object_detection.__path__ ['C:\\[中略]\\object_detection-0.1-py3.5.egg\\object_detection']
どうやら参照先が異なっているようだ。
このミスリードを招いているディレクトリを覗いてみたいと思う。
eggに関する解説は読み飛ばしてしまったが、その本質はzipであるらしい。
拡張子をzipにリネームすると、普通に解凍することが出来た。
そして肝心の中身がこちら。
どうやら、前なんとなくビルドしたデータがゴミになって残っていたらしい。
後書き
インポート系のエラーに遭遇したときは、その実態を覗いてみるとよさそうだ。
また、当たり前のことなのかもしれないが...
なんとなくビルドするのはやめよう
クソみたいな結論に至ってしまった。
追記:2017/07/05
なんか、タイムリーに似たような情報があがっていた。
*1:こういうのを許容できないから作業が遅い