「気分」の問題。
Cython, pure Python の2つ組で一つの機能を構築しようとしてるとして。例えば「優しさ」を取得する KindDetector なんて機能全体を
- _kind_detector.pyx
- kind_detector.py
みたいな構成で作っているとする。パッケージはいま app.kind だとして。
例外を通知しようと思うわけである。して、_kind_detector.pyx にて例外を定義する:
1 # filename: app/kind/_kind_detector.pyx
2 class MissingKindHumanoid(EnvironmentError):
3 pass
そして kind_detector.py でこうする:
1 # filename: app/kind/kind_detector.py
2 import app.kind._kind_detector
3 from app.kind._kind_detector import MissingKindHumanoid
ビルドして動くことを確認する。よしよし。
ただ、思うわけだ、「app.kind.kind_detector が公開インターフェイスなのだから、_kind_detector.pyx ではなく kind_detector.py が MissingKindHumanoid を expose するのが筋じゃないのか」と。
して、このようにするわけだ:
1 # filename: app/kind/_kind_detector.pyx
2 from app.kind.kind_detector import MissingKindHumanoid
そして kind_detector.py でこうする:
1 # filename: app/kind/kind_detector.py
2 import app.kind._kind_detector
3 class MissingKindHumanoid(EnvironmentError):
4 pass
ビルド出来るので実行してみる:
1 me@host: kind$ (cd ../../ ; python kind_sample.py)
2 Traceback (most recent call last):
3 ...
4 ImportError: cannot import name MissingKindHumanoid
なんでだぁ! と、叫びがちだけれど。
うん、このパターン、Cython 関係なく pure Python どうしだって出来ませぬ。依存の循環だからね。
なんでこれが Cython ネタなのか、と言えば、最初の前置き:「Cython, pure Python の2つ組で一つの機能を構築しようとしてる」がね、Cython では結構多いパターンだからなの。なんだかんだ、「Cythonプログラミングは楽しくない」というか、不愉快なところも多いので、必要なければ pure Python 維持部分は多い方が良くて、必要最小限だけ Cython 側で、ということは良くやるわけで。そうすると両者の役割分担にてたまにこういう「FAQ だろそれ」と言うようなところでもハマることがある、と。
これの解は?
パッケージの「__init__.py
」に書くことが解になるならそれが解と思いますよ。もはや「app/kind/kind_detector.py
」というモジュールの公開物ではなく「app.kind
」というパッケージの公開物になってはしまいますがね。たいがいそれでもいいんじゃねすけ?