静かなる名辞

pythonとプログラミングのこと



【python】cabochaのpythonバインディングの変な挙動

環境

 ubuntu 14.04
 cabocha 0.69
 cabocha-python 0.69

問題の概要

 変な挙動だった。というか率直に言ってバグなのでは?

>>> import CaboCha
>>> cparser = CaboCha.Parser()
>>> tree1 = cparser.parse("吾輩は猫である。")
>>> print(tree1.toString(CaboCha.FORMAT_TREE))
    吾輩は-D
  猫である。
EOS

>>> tree2 = cparser.parse("吾輩は猫ではない。")
>>> print(tree1.toString(CaboCha.FORMAT_TREE))
      吾輩は-D
  猫ではない。
EOS

 何やってんだよCaboCha! いや、「これで仕様通り動いてる。おまえの使い方が間違ってるんだ」て言われたら反論できないけど。詳細なドキュメントを見かけたことがないので、もしかしたらアホなこと(Parserのインスタンスの使い回し)をやっているのかもしれない。

回避するために試したこと

  • CaboCha.Parser("")する(コンストラクタに空文字列を渡す)

 効果なし。

  • 一度空文字列に対してparseを呼ぶ

 ここを参考に「もしかしたら効くかも」と思ってやってみた。
MeCabのparseToNodeのひどいバグ - 北野坂備忘録
 効果なし。

  • 文字列を変数に入れる、encodeする

 ここを参考に(以下略)。
MeCabをPythonから使う注意点とか - Shogo's Blog
 効果なし。encodeに至ってはやったら落ちた。

  • 仕方がないのでCaboCha.Parser()を毎回作る
>>> tree = CaboCha.Parser().parse("吾輩は猫である。")
>>> tree.toString(CaboCha.FORMAT_TREE)
Segmentation fault (コアダンプ)

 草も生えないとはこのことか。たぶんGC周りで死んでるんだろうけど、さて困った。

>>> parser1 = CaboCha.Parser()
>>> parser2 = CaboCha.Parser()
>>> tree1 = parser1.parse("吾輩は猫である。")
>>> tree2 = parser2.parse("吾輩は猫ではない。")
>>> tree1.toString(CaboCha.FORMAT_TREE)
'    吾輩は-D\n  猫である。\nEOS\n'

 一応回避できることはわかった。これで書くと極めて非python的なプログラミングを強いられるという問題はあるが、たぶんなんとかなる。

 ちなみに、ParserのインスタンスGCに回収されると treeだけ残っててもtoStringできないようです(Segmentation faultを吐いてくれる)。どんな作りになってるのかなんとなくわかってきたけど、率直に言って○○。

def parse(sentences):
    """
    sentencesは一文ずつに区切られた文のリストとして扱う
    """
    trees = []
    plist = []
    for s in sentences:
        parser = CaboCha.Parser()
        trees.append(parser.parse(s))
        plist.append(parser)

 このようなものを書いてあげれば、後からtreeを使うことができることがわかった。率直に言ってまったく嬉しくない。

問題原因の切り分け

 は、できてないです。
 

  • うちの環境固有の問題
  • cabocha-pythonの特定のバージョンの問題
  • cabocha-python固有の問題
  • cabocha固有の問題

 とりあえず逃げれることはわかったので、僕はやらない(明言)。

対策

 たぶん解析結果のtreeオブジェクトを使いまわそうという発想が間違っていて、cabochaのtreeオブジェクトを使わないで初手でXMLか何かに変換して取り扱うのが楽だと思います。そんなことを強いるバインディングって何よ? って気がしますが。

 もう面倒くさいから、JUMAN/KNPに鞍替えしようかなと思う今日この頃。