需要のないページ

プログラミングや趣味や。

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にリネームすると、普通に解凍することが出来た。

そして肝心の中身がこちら。

f:id:LouiS:20170701142351p:plain

どうやら、前なんとなくビルドしたデータがゴミになって残っていたらしい。

 

後書き

インポート系のエラーに遭遇したときは、その実態を覗いてみるとよさそうだ。

また、当たり前のことなのかもしれないが...

なんとなくビルドするのはやめよう

クソみたいな結論に至ってしまった。

 

追記:2017/07/05

なんか、タイムリーに似たような情報があがっていた。

*1:こういうのを許容できないから作業が遅い

/* コードブロック */