2007-07-29

clitter -- ChangeLog -> Twitter メッセージ送信ツール

今週もまたα版のスクリプトを公開した。(もちろんPythonで書いた。)

clitter -- ChangeLog -> Twitter message sender

"""
追記----
日本語ページも追加で作成しました。
clitter -- ChangeLog -> Twitter メッセージ送信ツール
"""

ChangeLogファイルから、Twitterに投稿するスクリプトです。
(上のサイトは自分のぐしゃぐしゃの英語で書いてみました。日本人でTwitterを使う人ってそんなにいるのかわからなかったので。。)

これを起動しておくと、あなたのChangeLogファイルに追加した項目がだだもれでTwitterに投稿されます。

ChangeLogファイルをいろいろ編集した際に、なるべく同じ発言を何度も送ってしまわないように、注意して投稿するかどうかを判定しているつもりですが、、もしなにかあったらすいません。

python-twitterを使っていますので、別途インストールしてください。

ちなみに自分のtwitterでの名前は hiroshiykw です。時々このツールでメッセージを送っているかもしれません。

追記----
なんでもかんでもChangeLogを送ってしまうのもなんなので、twitter用の独り言用ChangeLogをつくるのがいいかもしれません。
emacsなら、


(defun memo-twitter ()
(interactive)
(add-change-log-entry
nil
(expand-file-name "~/Documents/diary-twitter.txt")))
(define-key ctl-x-map "T" 'memo-twitter)

を、.emacsに書いておくと、C-x T で別ファイルでChangeLogが開きます。まずはこれでChangeLogファイルを作成しておいて、その後でclitterで~/Documents/diary-twitter.txtを読むようにして起動。

[メモ]C++作業 (やる気を維持するスクリプト)

会社で、Pythonで書いたプログラムのパフォーマンスを上げたいので、C++で書くことにした。

* 昨夜からすでに438行書いている。 "cat *.h *.cpp | awk '{if(length($0) > 2) print $0}' |wc -l" をcronで流して逐次行数が増えていくのを視覚化していくとやる気がでるんではないだろうか。リファクタの意欲が抑制されそうだけど。

* mac osx ではvalgrindが使えないそうな。これはやばいねえ。ある程度できたらLinuxにもっていくかな、、、、Linuxマシンは電源ファンがうるさすぎるので電源つけるのがいやだなあ。

* 会社で作ったものを、自宅で0から実装するのはライセンス的にどうなるんだろうというのはいつも思う。でも会社の業務のものすごい脇役のおかずのような部品だからまあ大丈夫だよね。

* 休日に趣味とは言え、半ば仕事のことをするのは不健康。

追記---
やる気を維持するスクリプトを作った。これをバックグラウンドで実行しておこう。


#!/bin/sh
# file: yaruki.sh

echo Yaruki script started..

while :
do
linenum=`cat *.h *.cpp | awk '{if(length($0) > 2) print $0}' | wc -l`
echo [yaruki] Lines: $linenum
sleep 300
done

追記---
やる気スクリプトのレポートしている行数がまったく増えていないときは、精神的ダメージがでかい。諸刃の剣とはまさにこれのこと。
チェック間隔を15分にしておいた。いったい自分は何をしてるんだろうという疑問が。

2007-07-28

Turbogearsについて思う3

昨日のPylonsのblogサンプルを参考にTurbogearsで同様のものを作ってみた。
昨日のままでは面白くないので、マルチユーザーにしたり、ユーザー登録機能をつけてみた。

その過程を記事にするのは大変なので割愛しますが、以下のような部品を使うと非常に簡単にできることがわかったのでその感想だけでもメモしておこう。

* registration
ユーザー登録のためのフォームや処理一切を用意してくれる部品。

* tgcrud
モデルオブジェクトを指定すると、そのCRUD機能の骨組みを用意してくれる部品。

感想
* registartion
- 非常に簡単。ひとつの設定ファイルにいくつか書くだけでよい。(登録メール送信のためのSMTP設定など)
- 登録フォームが英文なので、日本語のリソースファイルを用意する必要があるみたい。(未着手)

* tgcrud
- Turbogearsの作法が関係する部分をコマンド一つで全て生成してくれるので、やることはデータ更新フォームに何を表示するかぐらいを記述。
- registrationとのからみで、ユーザー登録した人しか削除、編集などを許可しないので、一部にチェック用の処理を書く必要がある。が、生成される骨組みコードがいたってシンプルなので、ものすごく簡単です。

* その他
- URLがちょっと見栄えが悪いのは、妥協して我慢した。あまり気になるならそれこそ前エントリに書いたRoutesを組み込むのが妥当か。。。

TG + registration + tgcrudの組み合わせで、アプリに必要な基礎部分はあっという間に手に入ることがわかった。
これは、Turbogears2が出るまではPylonsを保留してもよいなと思うよ。

というか、、、こういうのってRailsだとほんとうに当たり前にできることなんでしょうね。。。(-_- )

Turbogearsについて思う2

昨日のPylonsのblogサンプルと同等のものをTurbogearsで作ろうとしている。

昨日のものと同じようなものならすぐにできるので、ちょっと凝ってマルチユーザーのblogにしようと思って気づいた。

djangoの人たちが言う、TurbogearsではURLが引数だらけになるってのはこのことなんですね。
(うーん、自分がWEBの開発を数年勉強していないので、まるで浦島太郎のような気分だ。)

TurbogearsのURLの解決法が直接オブジェクトの階層をたどるものになっているので、ちょっと動的なページを作ろうと思うと、URLが?name1=arg1&name2=arg2...となってしまう。
マルチユーザーのブログならやっぱり/username/archive/200707とかにしたいではないですか。これがどうしたらいいか、、自分の今の実力ではなんかちょっと気持ち悪いコードになってしまう。

この点はTurbogears2で解決される予定なので、(というか、CherryPyがPylonsに置き換わるそうだ、)楽しみに待つか。。。
でも、Turbogearsのこれまでの資産が2に引き継がれるかすごく心配でもあるよ。

急ぐ人のためにこんな記事もある。
Using Routes with TurboGears
こうして微調整を重ねて良くしていけるっていうのはいいことですね。


Routes is a Python re-implementation of the Rails routes system for mapping URL's to Controllers/Actions and generating URL's.
(RoutesはRailsのURL→コントローラー/アクションマッピングのためのroutesシステムのリインプリメンテーションである。。。。)

でも、結局たいていの設計が、こうしてRailsの設計方針に収斂していくというのはなんだか「むきぃー!!」って思うね。

Turbogearsについて思う

Turbogearsの作り置き部品の一覧「The CogBin」をつらつらと眺めていたんだが、この充実ぶりはすごい。

Blogやフォトギャラリーの丸ごとのアプリや、画面に表示する部品、認証やユーザー登録のバックエンド部品、などなど様々なものがそろっている。

昨日作ったPylonsのサンプルに「そういえばユーザー登録機能を作んなきゃ」と思っていたところ、Turbogearsなら作らずとも完成品があるではないか。しかも、コマンド一つで組み込めるときている。

仕事ですごく簡易的な社内向けAPIを公開するのに、Turbogearsを使ってきてましたが、そんな裏方の役目にとどめず、こういう部品をいくつか組み合わせれば、あっというまに一サービスできあがってしまうんではないだろうか。

Turbogears2はPylonsと合流するという話を聞いているが、このままTurbogears1のままで枯れた技術になってくれればそれだけでもありがたいはずだ。

django一人勝ちと言われているが、でもTurbogearsって楽だよなあ。

Pylonsのサンプルを試した感想

前エントリー&前々エントリーでPylonsのサンプルを試して思ったこと。

* ちょっと引っかかったり(Pylonsの昔のバージョンをインストールしたり)したけど、合計2時間ほどで完了するちょうどよい分量でした
* Turbogearsなら、フォームや認証をほぼ自動生成してくれるんじゃなかったっけ?
* 4ヶ月前の記事がすでに現最新バージョンとは合わないというのは、よほど開発が高速に進んでいるんだろうか。
* perezvonの日記さんのチュートリアル記事はすごーーーくいい!
* 週末に腰を据えてやろうと思ってたが、この記事のよさのおかげもあって、寝る前のひとときで終わってしまったのはうれしい。
* 今回つくったものを、認証機能と簡単なモデルのCRUD機能の原型として、大事に今後使おうと思う。例えばこのサンプルを会社に持っていって、社内簡易ツールを作るベースにしようと思う。

* Makoは、、、まだいいや。

2007-07-27

Pylonsいきなりつまづく→でもうまくいく

いきなりつまづいている。

なんと最新のPylonsではテンプレートが標準でmakoにさしかわっているようなのだ!

ああ、どうしよう。Myghtyにもどすには、、、。

追記------
結局Pylonsのバージョンを0.9.4.1に落として実行している。
DepricationWarningというのがざくざくでながら動いていますが、、、

追記------
2まで無事完了した。Mysqlを使うことにしたよ。

追記------
3まで無事完了。画面が表示されるとすごくうれしいねえ。おもわず「おおお!」と声がでました。

追記------
4まで無事完了。すごい!記事を投稿できる!
ここまで1時間程度。

追記------
5まで無事完了。削除もできる!!!
なんて調子がいいんだろう。

追記------
6まで無事完了!
login_requiredデコレーターで、


from authkit.permissions import NotAuthenticatedError

が冒頭で必要であった。それからdecoratorモジュール初めて見たよ!これ使えばdecorator作りが簡単になるね。
しかし、この認証までこんなに簡単に作れるとは!!!
今頃気づいたが、

metadata = DynamicMetaData()

っていうのがmodel内にあるけど、これなに?後で調べよう。

追記-------
7まで無事完了!!
最後にブログのタイトルを日本語にしたときにテンプレートのエラーがでた。
自分のPythonのデフォルトエンコーディングがeucなので、utf-8で書いた設定ファイルの日本語をテンプレートに埋め込めないとのこと。
Pythonのデフォルトエンコーディングを変えるのは、他の自分のプログラムへの影響が心配なので、このサンプルをeucにつくりなおした。
でも、作り直しでも、DBのテーブル作成も一瞬でできるし、本当に表示にかかわる設定ファイルと、websetup.pyのテストデータだけをeucにするだけにした。
これがもし、websetup.pyのようなものをこしらえていない自作WEBアプリだったらと思うとぞっとする。こういうときに、優れたフレームワークはほんとにいいと思う。

週末はPylons

perezvonの日記さんに掲載されているPylonsでBlogを作る記事を週末にやってみようかと思います。

ちょっと順番に並べて一覧にしておく。

Blogを作る(1)プロジェクトを作る
Blogを作る(2)データベースの設定
Blogを作る(3) 記事の一覧・詳細
Blogを作る(4)記事の投稿・編集
Blogを作る(5)記事の削除
Blogを作る(6)AuthKitを使った認証処理
Blogを作る(7)表示関連の修正

よしやるぞー!

2007-07-26

[日記]OCamlのやる気をそがれる記事

OCaml Language Sucks
http://www.podval.org/~sds/ocaml-sucks.html

せっかく勉強しはじめたのにショッキングな記事。

たしかに、型を自動でキャストしてくれないとかは不便と思うけど。


# 2.0 ** 10.0;;
- : float = 1024.
# 2.0 ** 10;;
This expression has type int but is here used with type float

これぐらいは容赦してよと思う。

# #load "nums.cma";;
# open Num;;
# string_of_num (power_num (num_of_int 2) (num_of_int 10000));;
- : string =
"1995063116880758384883742162683585083823496831886192454852008949852943883022
19466319199616840361945978993311294232091242715564913494137811175937859320963
23957855730046793794526765246551266059895520550086918193311542508608460618104
68550907486608962488809048989483800925394163325785......略"

↑こういうのもPythonなら

>>> 2 ** 10000
1995063116880758384883742162683585083823496831886192454852008949852943883022
19466319199616840361945978993311294232091242715564913494137811175937859320963
23957855730046793794526765246551266059895520550086918193311542508608460618104
68550907486608962488809048989483800925394163325785......

で済んでしまうしなあ。
いや、しかしこれは逆にPythonが常に無条件にOCamlのbig_int相当を使っているからできているにすぎないということか。
ネイティブコードでの実行パフォーマンスを考えるとこういう込み入った仕様もやむなしか。

また、冒頭の記事にもあるように大きいintが桁あふれしてもなにも言わずに変な値になるというのも、ちょっとこわい。
速度重視の実装だから、やはり半分はC言語感覚で使えということだろうか。

いつもC++で書いてる時は、その場合場合に合わせて
「この変数はまあこの用途だから、unsigned intでいいよね、こっちはssize_tかなあ」
と想像しながら書くから問題はないんだけど。

OCamlをマスターするころにはこういうものはスッキリしてるんだろうか。

[日記]Pythonからの脱出

Pythonをすでに5年ほど使っていますが、あまりにもPythonを好きになってしまいました。

そのため、どこかで読んだんだけど「真のハッカーは毎年新しい言語を一言語習得せよ。」という教えを全く実践できていないのです。

他の言語を勉強していると、「Pythonなら同じものを0.5秒で書けるのに!」と思うこともしばしば。
特にcsvファイルの読み込みとかでいつもそう思います。

それで昨年はHaskellに挫折しました。(急にブームになったしね。)
また、電車の中で読んでたSICPもちょうど半分のところで挫折。やっぱ手を動かしてScheme書かないとだめだよねえ。ああ、次に挑戦するのはいつになることやら。

今はたまたまOCamlに先週から興味を持っているので挑戦中ですが、こんな調子ではすぐにやめてしまうかもしれない。
でも今のところ、もうすぐCSVの読み込みとかも書けそうなので、なんとか仕事で使えるようになるかもしれない。
理想的には今持っているPythonの各種自作ツールをOCamlでも活かすことができればいいんだけど。

しかし、今にして思えばPythonでCSVモジュールが標準添付になったのはたしかバージョン2.3の時だった。
そう思えば多少CSVの読み込みが標準でなかったとしても、Pythonに入門できていたことを思えば、今年こそは新言語をひとつぐらいは身につけるようにしなければ。

[日記]ocaml勉強 -- 文字列のjoin

splitをやったので、joinをやろう。


(* 文字列リストのjoin myjoin.ml *)

print_endline (String.concat "," ["aaa"; "bbb"; "ccc"])


感想
* これは簡単であった。String.concatという関数を使う。
* splitの時のようにstr.cmaを一緒にビルドする必要もない。

[日記]ocaml勉強 -- 文字列のsplit


(* 文字による分割 mysplit.ml *)
(* ビルドするには: ocamlc str.cma mysplit.ml -o mysplit *)

let strList = Str.split (Str.regexp " ") "aaa bbb ccc" in
List.map print_endline strList;;

感想
* Str.splitという関数がある。でも、正規表現(Str.regexpでつくる)で分けるみたい。単に文字列で分けるだけで十分なんだけど。。
* ビルド時に str.cma を必ず自分ファイルmysplit.mlより前に書かないといけない。
* List.mapでmap関数の動作をするようだ。でも、リファレンスの上から見ていったらArray.mapがあったのでそっちを使おうとしてめんどうになった。Listのほうだ。
* ListとArrayの違いを調べること。
* map関数は組み込みではないんだね。

2007-07-25

[日記]ocaml勉強 -- catコマンド

今日もocaml勉強。
ちょっと基礎からやることにしよう。


(* 標準入力から一行ずつ読み込んで表示する *)

let rec mycat line = begin
print_endline line;
mycat (read_line ())
end;;

try
mycat (read_line ())
with
End_of_file -> None
;;

感想
* print_endlineという「出力&改行」という関数があるよ。
* 例外を補足して終了か、、、うーん、もっといい手はないだろうか。
* mycat (read_line ()) を、haskell風に mycat $ read_line () のように書けないものだろうか。。。


参考までにPythonだと以下の通り。(しかしこれはちょっと手抜きだな)

#標準入力から一行ずつ読み込んで表示する
import sys

for line in sys.stdin:
print line[:-1]


邪道だがほぼ一行にするなら以下でもよい。

import sys

map(sys.stdout.write, sys.stdin)


うーん、このPythonのコンパクトさに、自分のocaml能力が追いつくのはいつの日か、、、。

[日記]ocaml勉強

初めてのプログラムとしてこんなのを書いた。これを書くのに2時間ぐらいかかった。
こんな書き方でいいのか非常に不安だ。だれか「勝手に添削」とかしてくれないだろうか。

今日の感想
* Pythonのようにimport文が不要なのはちょっと違和感がある。
* コーディングスタイルがわからない。ocamlにはPEP8みたいのがないだろうか。
* 「引数をとらない関数」って意味あるの?関数型言語ではそういう関数には意味ないような気もしてきた。これは深い話だろうからよく考えてみよう。
* 繰り返しの入出力を扱う場合にも再帰で書くんだろうね。ここで一瞬思ったのは、関数が(入出力の内容によって)毎回違う内容を返すのは変じゃなかろうかということ。これがおそらく(想像だけど)Haskellがmonadを持ち出す理由の一つなんだろうか。うーん難しい。
* 最後に「当たり」と表示する時に、"当たり¥n"というふうに改行を出力しないと画面に表示されないというところではまった。


(* 数字あてゲーム! *)

Random.self_init();;

let suuji = Random.int(100);;

let get_string_from_user kaisu question =
begin
Printf.printf "[%d] %s> " kaisu question;
read_line ()
end;;

let atetene num = suuji - num;;

let rec readinp kaisu =
let inp = get_string_from_user kaisu "数字は何でしょう" in
let ans = atetene (int_of_string inp) in
if ans = 0
then
print_string "当たり\n"
else if ans > 0
then begin
print_string "もっと大きいよ\n";
readinp (kaisu + 1)
end
else begin
print_string "もっと小さいよ\n";
readinp (kaisu + 1)
end;;

readinp 1;;

大人げない

今ここに一個大人げない記事を書いたが、数分で消しました。
ああ、自分って大人げない。。。。反省。寝よう。

[日記]SWIG-Python

今会社で作っているPython + C++のプログラムがメモリリークしている。

SWIG1.3がメモリリークしてないか気になったので、10000個の整数をvector<int>へ追加するのを10000回行う処理をさせていたが、macbookが悲痛な冷却音を出し始めたので、かわいそうになってやめた。

今日のテストの範囲ではリークはしていないようだ。

やはり会社でリークがおこっているのは他の部分なんだろうか。

2007-07-24

optparseはほんとすごいよね

急にoptparseモジュールが注目を浴びてるようです。deliciousのフィードにも挙がってたし。

optparse大ファンの自分の場合は、以下の内容を*.pyファイルを新規作成する場合のemacsのテンプレートとして登録しています。

今まで使い捨てで書いていた細かいスクリプトが、急に財産として蓄積しはじめるので、とても楽しくなりました。

以下のような内容を ~/.emacs.d/insert/python-insert.txt として保存。


#!/usr/bin/python
# _*_ coding: euc_jp _*_
# Copyright (C) 2007 Ayukawa Hiroshi

def main():
pass


if __name__ == "__main__":
import optparse

parser = optparse.OptionParser(u"""

""")
parser.add_option("-o", "--opt", dest="opt", help=u"", default=None)
(options, args) = parser.parse_args()

main()



次に、以下を.emacsに記述

;;テンプレート
(setq auto-insert-directory "~/.emacs.d/insert/")
(auto-insert-mode 1)
(setq auto-insert-query nil)

(setq auto-insert-alist
(append '(
("\\.py" . "python-insert.txt")
) auto-insert-alist))



これで、次から*.pyを新規作成するときは、強制的にoptparseを書くことを促されることになります。

余談ですが、Copyright文をあらかじめ書いておくと、公開への意欲も湧いてくるのでさらによいと思います。

他のPythonによる本文抽出ツール

自分で作ったあとにGoogleで検索して、すでにもっとすごいものがあるということに気づくという、いつものパータンですが、

webstemmer

という、より精度の高そうな本文抽出ツールを公開されている方がおられます。

こういうアルゴリズムは聞いたことはあったけど、Pythonですでに実装されているとは。

しかし、こういうのを作るってすごい。
いつかは自分もこういうものを作れるようになりたいと思います。

extbody -- PythonによるBlog&News本文領域抽出ツール

Pythonで、BlogやニュースのWEBページから、本文領域のHTMLを抽出するツール

extbody -- Blog&News本文領域抽出ツール

を作りましたので公開します。

いつものごとくα版です。(そろそろいいかげんに、ひとつひとつきっちりと作ったほうがいいよね。)

以前から、他のアプリの一部として使っていたものを分離してモジュールにまとめたものです。

* 正解率8割程度。(2ch抜粋系blogにはめっぽう弱いです。)
* 日英対応。

です。

中身は試行錯誤が複雑にからまった呪文のようなソースになっておりますことをご了承ください。

最初はPython標準のHTMLパーサーや、有名なBeautifulSoupを使ってましたが、時折解析できないHTMLがありましたので、結局自筆の正規表現で解析しています。

おおざっぱにtableタグとdivタグぐらいの対応が少なくとも合っているソースであれば解析できます。

本文領域決定の計算は、なかなかむずかしく、残り2割を正解にするのは超むずかしいところです。

アルファ版とか言ってますが、次はひとまずソースの整理をせねばなりません。

[メモ]句読点は「&#12290;」

このブログのHTMLソースでは、句読点「。」が&#12290;という記述になっている。
これのせいで現在作成中の解析スクリプトがなかなかうまくうごかなかった。
面倒くさい。
公開は明日以降にしようかな。

2007-07-21

SAContextで複数DB

昨日のTODOに挙げていた、「SAContextのまとまったドキュメント探し」であるが、SAContextのソースの冒頭のコメントがすごくまとまっていることに気づいた。
特に、複数DBの扱いも当然のように書かれていることはとても好印象だ。

ちょっと試してみたのがこれ↓


ayu@~% python
Python 2.5.1 (r251:54863, Jun 17 2007, 08:50:55)
[GCC 4.0.1 (Apple Computer, Inc. build 5367)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from sqlalchemy import *
>>> from sacontext import *
>>> sac = SAContext()
>>> sac.add_engine("DB1", "mysql://ayu:ayu@localhost/test")
(, MetaData())
>>> sac.add_engine("DB2", "mysql://ayu:ayu@localhost/test2")
(, MetaData())
>>> table1 = Table("table1", sac.get_metadata("DB1"), autoload=True)
>>> table2 = Table("table2", sac.get_metadata("DB2"), autoload=True)
>>>


これで、会社で使うのに何の問題もなくなった。

2007-07-20

[記録] Pylons の入門記事を読んだ

「Pylonsで簡易Wikiを作ってみる」と、公式のQuickWiki Tutorialに従ってwikiを作ってみた。
SAContextの実例を上の記事で見ることができたのがうれしい。ウノウの方のPython記事は毎回ためになるなあ。
(しかし、SAContextの人は北斗の拳の敵(のちょい役)みたいだね。)

djangoやTGをまともに触っていないんだけど、Pylonsは一番しっくりきそうな気がした。

TODO:
 認証について調べる。
 SAContextのよりまとまった記事を探す。
 Makoドキュメントを斜め読み。
 

2007-07-19

[メモ] ちょっとやそっとでは、Python nativeのlistには勝てないことがわかった

C++のstd::vectorを、std::vector<PyObject*>として、Python拡張に仕立て上げて、Python nativeのlistと対決させてみた。
結果、圧倒的にPythonのlistの勝利↓


>>> t = timeit.Timer("for i in xrange(10000): ap(1)", "import vecpy; v = vecpy.vecpy(); v.reserve(10000); ap = v.append")
>>> print t.timeit(number=100)
0.235954046249
>>> t2 = timeit.Timer("for i in xrange(10000): ap(1)", "v = []; ap = v.append")
>>> print t2.timeit(number=100)
0.115885019302


std::vectorのreserveメソッド、いけると思ってたんだけどなあ。
Python拡張を呼び出すオーバーヘッドがなんか特別にあるってことだろうか。

2007-07-18

明日のTODO

昨日のstd::vectorへの要素の追加でなんかリークしてるみたいなのを調べる。

C++でPython拡張

今日も(睡眠時間を削って)Python拡張の勉強をした。
今日は苦手なC言語ではなく、かすかにましなC++でPython拡張を書くことに挑戦。
試しに、std::vectorをPythonから使うものを書いてみたが、vectorの作成、push_back(), size()を使えるとこまできた。
もう少し実装が進んだら、Pythonのlistとstd::vectorを対決させてみようと思っている。
Python拡張歴3日なので、全くの未熟者で恥ずかしい部分も多々あるとは思うのですが、今日の作業で作ったC++対応のPython拡張のためのテンプレートをコピペしておこう。
ちなみに「boost使うと、、」というツッコミはなしでお願いします。


#include <Python.h>
#include <structmember.h>
/*
## Copyright 2007 Hiroshi Ayukawa (email: ayukawa.hiroshi [atmark] gmail.com)
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
*/

/*
説明
このテンプレートは、Pythonモジュールで型を一つ定義するテンプレートです。
最初にこのファイルを、あなたのプロジェクトに合わせて別名で保存します。
その後、このファイル中の
mytype
という文字列を一括置換で、あなたが定義しようとしている型名に変換します。

基本的にC言語で書いてください。
C++も使えます。その場合はファイルの拡張子を.cppにしたほうがいいかもしれません。(未確認)
C++の場合、公開メソッドは必ず extern "C" 宣言してある必要があります。(そのため、このテンプレートは随所にその宣言があります。)
メソッドを追加する場合はお忘れなきように。

*/

typedef struct {
PyObject_HEAD;
// TODO: ここに型のメンバーを宣言
} mytype;

#ifdef __cplusplus
extern "C"
#endif
static void
mytype_dealloc(mytype* self)
{
// TODO: この型の掃除処理を書く。
self->ob_type->tp_free((PyObject*)self);
}

#ifdef __cplusplus
extern "C"
#endif
static PyObject *
mytype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
mytype *self;
self = (mytype *)type->tp_alloc(type, 0);
// TODO: ここで型のヌル初期化処理を書く
return (PyObject *)self;
}

#ifdef __cplusplus
extern "C"
#endif
static int
mytype_init(mytype *self, PyObject *args, PyObject *kwds)
{
const char* mecabOpt = NULL;

// TODO: 引数処理。ここは適宜書き換えてください。
if(PyArg_ParseTuple(args, "")){
}else{
if(PyArg_ParseTuple(args, "s", &mecabOpt)){
PyErr_Clear();
}else{
PyErr_SetString(PyExc_TypeError, "bad argument(1)");
return -1;
}
}

// TODO: 型の初期化処理を書く。

return 0;
}

static PyMemberDef mytype_members[] = {
// TODO: 公開メンバの設定。
// like this... {"getMecabOpt", T_STRING, offsetof(mytype, mecabOpt), 0, "mecab option"},
{NULL} /* Sentinel */
};

/* method definition example
// TODO: メンバ関数の定義
#ifdef __cplusplus
extern "C"
#endif
static PyObject *
mytype_parse(mytype* self, PyObject* args)
{
//......
}

// method list
// TODO: メンバ関数の宣言
static PyMethodDef mytype_methods[] = {
// like this... {"parse", (PyCFunction)mytype_parse, METH_VARARGS,"Return the parsed result."},
{NULL} // Sentinel
};
*/

//Type declaration
// 型の宣言、基本的にはこのままでたいていはOKと思われる。
static PyTypeObject mytypeType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"mytype.mytype", /*tp_name*/
sizeof(mytype), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)mytype_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
"mytype objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
mytype_methods, /* tp_methods */
mytype_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)mytype_init, /* tp_init */
0, /* tp_alloc */
mytype_new, /* tp_new */
};

static PyMethodDef module_methods[] = {
{NULL} /* Sentinel */
};

#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
#ifdef __cplusplus
extern "C" {
#endif
PyMODINIT_FUNC
init_mytype(void)
{
PyObject* m;

mytypeType.tp_new = PyType_GenericNew;
if (PyType_Ready(&mytypeType) < 0)
return;

m = Py_InitModule3("_mytype", mytype_methods,
"Example module that creates an extension type.");

/* in case you would make static global variable
// TODO: ここで静的Globalなどを必要に応じて作る。
SURFACE = PyString_FromString("surface"); // SURFACE shold be declared on the top of this source code like "PyObejct* SURFACE;"
if(SURFACE == NULL) return;
if(PyModule_AddObject(m, "SURFACE", SURFACE)) return;
*/

Py_INCREF(&mytypeType);
PyModule_AddObject(m, "mytype", (PyObject *)&mytypeType);
}

#ifdef __cplusplus
}
#endif

2007-07-16

[メモ] mercurialルーチンワークメモ

Pythonで書かれた、バージョン管理システムmercurialのルーチンワークメモ。
Pythonでプロジェクトを作る場合。


0. プロジェクトのルートを決めて、手始めになにかおもむろに作り始める。

1. ほどよく出来上がってきたら、ゴミファイルを削除し、プロジェクトルートでhg initをタイプし、最初のリポジトリにする。

2. プロジェクトルートに.hgignoreというファイルを作り、以下を記述。


syntax: glob
*~
*.o
*.pyc
*.prof
.DS_Store

ここに書いたファイルはmercurialに登録されない。
*.profはpythonのhotshotプロファイラの出力として使うことにしているので、登録しない。
.DS_StoreはOSXが勝手に作るものみたいなので、これも登録しない。

3. hg statusをタイプし、状況確認。

$ hg init
? .hgignore
? benchmark.py
? cmecab.c
? cmecab/__init__.py
? docs/index.html
? docs/memo.txt
? setup.py
? testtext.txt

ここで?がついているものが、次の手順で登録される。
もし、よけいなファイルがあるなら、削除するなり、.hgignoreに追記。

4. hg add をタイプし、リポジトリに登録。hg commit でコミット。

5. 以後、ファイル修正、追加などしたら、hg statusやhg addで確認、追加し、まとまったらhg commit。

6. ログはhg logで閲覧できる。

2007-07-15

[メモ] Python C/APIを使っていて、気づいたこと、作法など

Python標準のlistやdictを関数から返すときはそのまま普通につくって返す。しかし、そこでキーなどを設定するときに作ったオブジェクトはDECREFしておくようだ。(多分)
うーん、しかし、こんなに煩雑になるんだけどいいんだろうか。。。


PyObject* getSomeDict(PyObject* self, PyObject* args){
PyDictObject* result = PyDict_New();
if(result == NULL) return NULL;

PyStringObject* key = PyString_FromString("age");
if(key == NULL){
Py_DECREF(result);
return NULL;
}
PyIntObject* value = PyInt_FromLong(32L);
if(value == NULL){
Py_DECREF(result);
Py_DECREF(key);
return NULL;
}
if(PyDict_SetItem(result, key, value) == -1){
Py_DECREF(key);
Py_DECREF(value);
Py_DECREF(result);
return NULL;
}
Py_DECREF(key);
Py_DECREF(value);
return result;
}

cmecab -- Mecab-Pyhton高速バインディング

前から作ろう作ろうと思っていたものを作った。

cmecab -- Mecab-Pyhton高速バインディング

標準のmecab-pythonバインディングでは一語ずつPython側に返すので、大量のテキスト(数十Gレベル)を処理する際に、なかなか処理時間がかかります。

これを一語ずつと言わず、パースしたものすべてをC言語側でまとめて一度でPython側に返すようにすることで高速化をはかります。(なんと乱暴な)

標準のmecab-pythonでいう、parseToNode(...)の(...)の部分の結果をまとめて一気に返すイメージです。
そんなことしてメモリは大丈夫なのかという不安がよぎりますが、ちょっと試しに使ってみることにします。

今作ったばかりのアルファ版ということで前もって言い訳を書いておきます。

* 実際の大量のテキストでのテストは連休明けに自分の勤め先で実際にこれを使って行います。(職場の人ごめん)
* メモリリークチェックにはまだかけてないよ。(どうすればPython拡張のリークチェックができるんだろうか。)
* Python C API初心者の自分が書きました。
* ちなみにC言語を使うのは12年ぶり。(C++は時々使ってましたが。)

参考ページ: Python拡張の作り方

2007-07-13

設定完了



blogの設定が完了した。
* Emacsから投稿できるようにした。
* ページのデザインを選んだ。
たったこれだけに1時間ほどかかるとは。