HOME | ドキュメント |  ブログ  |  BBS  |  瓦版  | 将棋プロジェクト |  物置小屋   

象歩 ドキュメント

Categories
Zope (46 items)
歳時記 (26 items)
工作 (19 items)
将棋 (25 items)
料理 (2 items)
Vine (27 items)
Squeak (2 items)
(1 items)
雑記 (4 items)
Python (19 items)
ZOPE3 (3 items)
Linux (6 items)
(1 items)
道具 (3 items)
買い物 (1 items)
PC工作 (2 items)
ボート (3 items)
Recent Entries XML
Recent Comments
Recent Trackbacks
Archives
Python
パイソンは高級言語です

26 June 2004

TCPWatch-1.3

急遽カテゴリに python を追加しました (爆
Python  

この処なぜかパケットを覗くことが多くてtcpwatchを使ってます。手軽で便利です。最近では ここ で紹介されてますが proxy や forwarder として使えます。

1.2.1 までは tcl/tk ライブラリが "--enable-threads" でビルドしてある環境だとダイアログが立ち上がらなかったのだけど、1.3 で 対処 されたのが確認できました。実際 VineSeed では、これが原因で立ち上がらなかったのですが。


以下はローカルに httpd などが稼働している場合の例です。

proxy 型接続の例

$ python tcpwatch.py -p localhost:3128 &
tcpwatch のダイアログが表示される
$ telnet localhost 3128

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
"HEAD http://localhost/" で尋ねる
HEAD http://localhost/ HTTP/1.0 [ENTER]
[ENTER]

HTTP/1.1 200 OK
...
...
Connection closed by foreign host.

forwarder 型接続の例

$ python tcpwatch.py -L localhost:3128:localhost:80 &
tcpwatch のダイアログが表示される
$ telnet localhost 3128

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
"HEAD /" で尋ねる
HEAD / HTTP/1.0 [ENTER]
[ENTER]

HTTP/1.1 200 OK
...
...
Connection closed by foreign host.

18 July 2004

L.L.Weekend

Python   Squeak  

LL Weekend がまた開催される。あつい夏になりそう。
東京で仕事していた頃は、こういう企画があれば気軽に参加できる環境に居たわけだけど、なんとかの有難味は失ってみないと分からない。二日連続では無理かなー


プログラムの予定 を見ると、とても面白そう。
「LL を仕事に」使っていますが、納品物件にもぐり込ませるまではいかない状態。
「君ならどう書く」n-Queens ゲームをどう書くのか興味深々。ブラボーと喝采できるものを見たい^^
「LLとblog」では blog の問題点が明らかになるような気がします。将来の見通しも知りたい。
「その場でどう書く」うん十年前ならまだしも、ああ胸が切なくなります。
懇親会も行きたいな。怖いものみたさで。仕事まじめにやればいけるかな。

08 August 2004

L.L.Weekend

外野席から
Python   Squeak  

Matzにっき に nQueen の観戦記あります。Squeak 強し。 sumim's smalltalking-tos 読むと林さんの nQueen は全戦全勝だったらしい^^ そして梅澤さん (Squeak) のデモは大うけだっだと。

一方 turkyさん の記事 見ると Python ではイテレータ、ジェネレータのお勉強ネタ。メモ(^_^)β... nQueen のお題では Python 陣営頑張りすぎたのか;? おおしまさん曰く 「処理系が速いのがSqueakの良いところのひとつでもありますね」とのこと。

でも本当のところは会場に行ってみないと判らないでしょうね、自分は外野席で寂しくテレビを見ておりました。 アジアカップ優勝バンザイ ^..^


02 February 2005

SpamBayes 日本語化

spambayes japanese localize
Python  

SpamBayes はベイズ理論を利用したスパムフィルタです。 Python で書かれています。

軽くてフィルタ効率が良いと評判のプログラムなのですが、日本語メールに対応していません。 スパムメールを振り分ける時に Subject が文字化けしてしまい困ります。 統計に人間の意志を加味するところが肝ですから残念。 ちょっとだけ修正してみました。

とりあえず Subject の文字化け対処と、 マウスカーソルを上に持って行ったときに出るサマリ表示はうまくいきました。 パッチは (ProxyUI, PyMeldLite) の二つです。 これは試験版 (無保証、無責任) なので、利用なさりたい方は覚悟の上でどうぞ。



課題はもう一つあって、日本語トークンの分離ができていません。 日本語メールの場合フィルタ効率が落ちるという話もあります。 また中文やハングルの場合どうなるのか解かりません。 まあ、Subject と本文だけで判定してる訳でもなさそうなので、 そうでも無いと思ってますけど。

ちゃんと日本語化するには日本語版 (または CJK) スプリッタを追加して、 トークンを抽出し、その結果の評価をしないといけないのかもしれません。 今は手に余るので、使ってみて気が向けばそのうち試すかもしれません。 # 敵は本能寺?

02 March 2005

CJKSplitter と UnicodeBlockTokenizer

異種格闘技戦というか一回戦;;
Python  

python 2.4 になると CJKCodecs が組み込みですが、兄弟のような名前の CJKSplitter はどんなもんなんだろうか? python2.3 環境で試してみました。

cjksplitter-0_7_1.tgz を解凍して実験。 zope モジュールを使うのでパスも通します。

$ cd CJKSplitter/
$ export PYTHONPATH="/usr/lib/zope/lib/python"
$ python
>>> from CJKSplitter import CJKSplitter
>>> u = unicode("漢字とカナabcだー!!oz,012 ^^ そんな※(−−;)", 'euc-jp')
>>> for x in CJKSplitter().process([u]):
...    print x.encode('euc-jp')
...
漢字
字と
と
abc
だ
oz
012
そん
んな
な
>>>
う〜ん、README.txt に書いてある通りでした。 漢字は 2 文字づつ、しかも重複して分割する。 日本語の場合には仕様が合わないと思う。

追記: ごめんなさい。これは無知を背景にした脊髄反射的な誤解ですね。 フカマチさんの日記 (2006/01/06) にとても判り易い説明があります。

それではと、 UnicodeBlockTokenizer を試してみた。


こちらは普通の python モジュールとして実行、

$ python
>>> import unicodeblock_tokenizer
>>> u = unicode("漢字とカナabcだー!!oz,012 ^^ そんな※(−−;)", 'euc-jp')
>>> for x in unicodeblock_tokenizer.tokenize(u):
...    print x.encode('euc-jp')
...
漢字
と
カナ
abc
だ
ー
!!oz,012
^^
 
そんな
※
(
−−
;
)
>>>
ロ−カルなプログラマとしては素直なこちらを使いたい気持ち。ascii 文字列に関しては再度 splitter をかければ良いし、他の漢字圏の文法は知りませんから。

04 March 2005

IE で PNG 透過表示ができない?

PIL (Python Imaging Library) にパッチをあてる
Python  

雪山でキャンプしてる人達や、雪のため電車が遅れて打ち合わせに参加し損なった人が居る中で、のんびり 将棋界で一番長い日 を楽しもうと思ったのだけどやっぱり無理でした。

象歩の将棋盤は Python Imaging Library (PIL) を使ってダイレクトに PNG 画像を作ってるわけですが、 IE6.x では PNG の透明画像をうまく表示できないようです。 256 色パレットの透明色は表示できるようなのですが、RGB + αチャネル付きが表示できません。 他のブラウザでは表示できてるから書いてるのですが。

少しだけ調べてみると PNG ファイルのヘッダに bKGD chunk ブロックを追加するとうまく表示できるらしいと判りました。 これは必須 chunk では無いので IE のバグでしょう。 ということでパッチ Imaging-1.1.4-PIL-RGBA.patch を作成。これで一応背景色は透けて見えます。


ですが、背景が画像の場合はやはり透過表示になりません。このへんは IE の根本的な設計不良な気がします。 http://www.libpng.org/pub/png/pngapbr.html にいろいろ書いてあるけど深追いはしない。

最後にツールを紹介。 pngcheck は便利です。 PNG 形式 をチェックできます。たとえばこんなふうに、

$ pngcheck -v game2.png
File: game2.png (28225 bytes)
  chunk IHDR at offset 0x0000c, length 13
    510 x 354 image, 32-bit RGB+alpha, non-interlaced
  chunk bKGD at offset 0x00025, length 6: red = 255 green = 255 blue = 255
  chunk pHYs at offset 0x00037, length 9: 2835x2835 pixels/meter (72 dpi)
  chunk tIME at offset 0x0004c, length 7:  4 Mar 2005 02:44:17 GMT
  chunk IDAT at offset 0x0005f, length 8192
    zlib:  deflated, 32K window, maximum compression
  chunk IDAT at offset 0x0206b, length 8192
  chunk IDAT at offset 0x04077, length 8192
  chunk IDAT at offset 0x06083, length 3498
  chunk IEND at offset 0x06e39, length 0
No errors detected in game2.png (96.1% compression).
chunk タグを表示できます。

06 March 2005

PIL Imaging-1.1.5c1

Python  

Imaging-1.1.5c1 が公開されていました。 PNG 保存時に補助情報 (chunk) を指定できるようになってたので、 パッチ は不要です。

dpi は引数で直接渡し、 その他の補助情報は PngInfo インスタンスに格納して渡すことができます。

from PIL import Image
from PIL.PngImagePlugin import PngInfo

im = Image.new('RGBA',(200, 200),(0,0,0,0))

# 画像描画処理をおこなう

info = PngInfo()
info.add('bKGD', '\000\377\000\377\000\377')
im.save('img-rgba.png', 'PNG', dpi=(72,72), pnginfo=info)


pngcheckで確認してみると

$ pngcheck -v img-rgba.png
File: img-rgba.png (3601 bytes)
  chunk IHDR at offset 0x0000c, length 13
    200 x 200 image, 32-bit RGB+alpha, non-interlaced
  chunk pHYs at offset 0x00025, length 9: 2835x2835 pixels/meter (72 dpi)
  chunk bKGD at offset 0x0003a, length 6: red = 255 green = 255 blue = 255
  chunk IDAT at offset 0x0004c, length 3505
    zlib:  deflated, 32K window, default compression
  chunk IEND at offset 0x00e09, length 0
No errors detected in img-rgba.png (97.7% compression).
解像度 pHYs と背景色 bKGD がちゃんと追加されています。

02 April 2005

Python2.5 以降は TAB 禁止?

Python  

エイプリルフールねたで辟易していたら、寝しなにトドメをさされた感じ。 Guido さんが Stricter Whitespace Enforcement と云うお題で書いてます。 PyJUGもたちが悪い。 Python の新たな構文 なんてマジで解説してます。

これは困りました。 私は vi (vim) 使いなので、キーストロークが少なくて済む「TABを使う派」なのです。 えーTAB使えなくなるんですか? タブがタブーなんて言ってる場合じゃないですよね。

確かに Python の最大の長所であり、かつ究極の弱点はインデントだと感じてたのですが。 これではエディタ選びから始めないと Python2.5 以降使えないですね (T.T)


09 April 2005

P2Pで将棋(の準備)

Python  

XMLRPC は難しいのかと思えば、 smallp2p など参考にすると意外に易しいのかも。 鯖立てるのは下記のようなコード server.py でとりあえず可能でした。

#!/usr/bin/env python
from SimpleXMLRPCServer import SimpleXMLRPCServer
import sys, socket

class RPCMethods:
    def next(self, s=''):
        print 'received:', s
        return 0

def main():
    sv = SimpleXMLRPCServer((socket.gethostname(), int(sys.argv[1])))
    sv.register_instance(RPCMethods())
    sv.serve_forever()
    
if __name__ == "__main__":
    main()

起動は

$ python server.py <ポート番号>


一方クライアント側のコード client.py はもっと簡単、

#!/usr/bin/env python
import sys, xmlrpclib

def main():
    peer = xmlrpclib.ServerProxy('http://' + sys.argv[1])
    s = raw_input('>>')
    while s:
        peer.next(unicode(s, 'euc_jp'))
        s = raw_input('>>')

if __name__ == "__main__":
    main()

下記コマンドで起動します。

$ python crient.py <鯖のURL:ポート番号>
これでクライアント側で入力した文字がサーバ側に表示されるはずです。

双方向にすれば、チャットのようなソフトができあがります。 たとえば将棋盤にくっつければ即P2P将棋が出来るはずです。 Zope鯖に組み込んでも面白そう。 Python のすごさを実感しました。

技術的にはありふれたもので、他所かに載ってそうなコードですが、 これは BBS での会話 の証拠のつもり。今の仕事を早く終わらせて、作ってみたいなーと現実から逃れてます。

28 August 2005

SpamBayes 日本語化 (2)

spambayes japanese localize
Python  

前回の SpamBayes 日本語化 は、GUI 画面だけでしたが、今回は、日本語トークンの抽出を試みました。 トークンの抽出は、 UnicodeBlockTokenizer を改造して使用しています。 処理速度を上げるため generator 化しました。 また ascii 文字列も分割した方が良さそうでしたので、稚拙なコードを追加してあります。 今後、トークン分割で勝手にコードを追加して行くことになると思うので、 モジュールの名前は変更しました。

ソースとパッチは ここ にまとめて置いてあります。 日本語トークンはとりあえず utf-8 でエンコードされた str 型で返してます。 本来は unicode 型で返したいところですが、 その後の処理を調べてませんので。

今回は tokenizer コードに手を入れただけで、 トークン抽出以降の処理はまったく調べていません。 とは云え (運良くこのまま) ベイジアンフィルタ処理部分が通してくれれば、 何もしないで動く可能性はあります。まあ、その反対は地獄と云うこと。 その話は、また次の機会ってことで、かんべん。


31 August 2005

SpamBayes 日本語化 (3)

spambayes japanese localize
Python  

POP3 Proxy 動作 (sb_server.py) させてみました。 面白い^^。日本語もちゃんと評価されてる様子で、少し期待してます。 ブラウザで表示して見ると、日本語表示があちこち文字化けして、みっともないので 修正版 を置きました。このまま問題が出なければ、 週末に家の imap 鯖のフィルタとして組み込んでテストするつもりです。

spambayes-1.0.4-*-patch に関しては、みたところ spambayes-1.0.31.0.4の該当ソースに変更は無いので、 1.0.3にもそのまま当たると思います。 (> debian 方面の方)

メールからトークンを抽出する tokenizer.py の出力は、 オリジナルは str 型ですが、 日本語のところだけ、思い切って unicode 型にしてみました。 今のところ問題は起きて無いように見えます。 またオリジナルの性能を損なうのを嫌って、修正は最小限にしたつもりです。 具体的には subject と、body (tokenizer.py の最後で単純に本文からトークンを抽出する部分)を日本語対応にしただけです。


トークン抽出は、わかち書きや 2-gram 処理等は考えず、 単純に UTF-8 コードによる分割 (ひらがな、カナ、漢字、英記号など) のみ行ってます。 元々 SpamBayes 自体がトークン分割しかしてません (?) ので、 出発点としては安易な方法を選びました。 なにしろ、何も手を加えなくても、かなりの能力を発揮してるスパムフィルタなので、 日本語に関して、ほんのちょっとだけ賢くなってもらえれば十分と思ってます。

もし何かアイディアを試したくなっても、たとえ運用に入ったとしても、日本語スプリッタ SplitterForU.py を差し替えるだけで済むはず、という考え。 (その前にドキュメント読まないといけないのですが)

01 September 2005

角をためて牛を殺す

少しだけ曲がっている牛の角を真っ直ぐに直そうとして牛を殺してしまうこと
Python  

spambayes を POP3 Proxy として使ってみると、 from header やら subject の切り落としなどで文字化けしてます。 直そうと云う気が起きましたが、思い留まりました。

改めて tokenizer.py のソースを見ると、 subject と body の日本語対応だけにして置いたのは、結果的に良かったと思ってます。 オリジナルソースのコメントを読むと、いろいろ試行錯誤してたどり着いたことが見えます。 考えも無く修正を加えるのは愚かなこと。 オリジナルソースを汚すのは最小限にしないといけません。

それよりも、ベイズフィルタ部分を理解するのが先だし、 今のところ日本語スプリッタを深追いする気もありません。 web インターフェースは spambayes-1.1a を見ると i18n 化が始まってるようです。 しいて手を加えるとすれば、 rpm パッケージに POP3 Proxy 用 daemon スクリプト を追加し、ついでに Sylpheed との連携を考えることくらいです。 モー少し便利になるかもしれません。


余談ですが、今日下記のメールが三通も届きました。

毎回、数多くの方にご参加いただき、**** 参加の登録もすぐに満員となって
しまいますので、お早めのご登録をおすすめいたします。
開催情報および参加登録はこちらから↓
http://www.****.jp:****/****/
■主な特別企画
今回の **** では、次の特別企画をご用意しております。            
★来場者アンケートプレゼント
会場にご来場いただき、**** に関する意識調査アンケートに
ご協力いただいた方から抽選で **** などをプレゼントいたします。

そのトークン分析表を眺めてみると、スパム寄りの単語ばかり並んでます。 私の判定は、メールが長文なことも考慮して若干スパムなんですが、 ベイズ君は ham と判定しました。 hamspam の違いは紙一重のように思えます。 さて、どちらの投票箱に入れようか?

05 September 2005

スパムの月別集計

spambayes japanese localization
Python  

下記テーブルはオリジナルの SpamBayes を導入してからの集計です。 procmail のログから抽出しました。 「総数」は受信したメールの総数です。 「未判定数」は、スパムだけで無く、必要なメールも含んだ数です。

総数 (recieved) 未判定数 (unsure) 比率 (unsure ratio) スパム (spam) 非スパム (ham)
2 581 59 (15) 0.102 (0.026) 261 ( 14) 261 ( 190)
3 6,152 208 (61) 0.034 (0.010) 2,317 (126) 3,627 (2,473)
4 5,750 72 (39) 0.013 (0.007) 2,266 (162) 3,412 (2,328)
5 6,065 48 (18) 0.008 (0.003) 2,809 (155) 3,208 (2,191)
6 5,710 87 (35) 0.015 (0.006) 2,774 (178) 2,849 (2,076)
7 5,409 113 (91) 0.021 (0.017) 2,309 (256) 2,987 (2,194)
8 4,914 54 (37) 0.011 (0.008) 1,669 (137) 3,191 (2,218)
9 438 5 ( 3) 0.011 (0.007) 139 ( 10) 294 ( 175)
total 35,019 646 (299) 0.018 (0.009) 14,544 (1,038) 19,829 (13,845)
括弧の中の数字は、日本語メール (subject に iso-2022-jp, shift-jis, utf-8 が含まれていたもの) の値です。 比率の場合は、月別総数に対する日本語メールの未判定率です。


データを保存してないので、正確には判りませんが、 記憶によれば、誤ってスパムと判定されたメールは無かったと思います。 逆に ham の中に見逃されたスパムが発見されることはありました。 まあ実害は少ないのですけど。 最終的に、 unsure (判定できないもの) は 1 〜 2% くらいまで減少したようです。 半年くらいの間に順調に減ってるように見えます。 (それにしてもスパムの数が多いなー)

日本語メールについては、オリジナルのままでも、かなり良好な判定をするようです。 ただし、初期の頃を除いて、学習効果があるようには見えません。 七月くらいから、日本語のやけに上手なメールが増えました。 ベイズ君は少しついていけなかったようです。 私もついていけません。 そんなわけで、昨日から 日本語対応 SpamBayes に切替えて運用してます。 果して、日本語トークン分析の効果は表れるのでしょうか? 。。。つづく

22 September 2005

スパム阻止率が 99.5% 越えてる

Python  

この一週間はスパム判定できなかったものが 0.45 % までになりました。 受信メールが 1117 件で判定できなかったものが 5 件。 判定ミスは 0 件です。 しかも判定できなかったメールはアマ*ンや*ラットホームからのダイレクトメール等、 自分でもどちらに振り分けようか悩んでるものでした。

新しいパタンのスパムが来れば、即座に判定できない可能性はありますが、 それを振り分けるのも面白いと感じるようになってきました。 この前、某メモでフレームになりかけた投稿があり、 ほぼスパム判定 (unsure) されて迷ったのですが、一応受け取ること (ham) にしました。

ところで spambayes-1.0.3 のパッチを持って行かれる方がいらっしゃります。 信用できないから web インターフェースのパッチだけで良いと云う場合は構わないのですが、 日本語トークン分割した spambayes-1.0.4 は、こちら ですので、興味ある方には試して貰えるとうれしい。 Vine-3.2 の方は extras を有効にすれば、apt-get で即入ります。


スパム判定はもう落ち着いた気がしてます。 最終的な結果は来年か再来年にでも書きます。 今は次の使い道を考えてるところです。 spambayes をデーモンで常駐させて置き、sylpheed や blog, bbs, chat などで気軽に使いたい、 なんて考えてます。とりあえず、もう少し使い易くしたいなと。 で、他にも使い道があるのでは無いかと思案中。。。

04 May 2006

SpamBayes この一年の集計

Python  

SpamBayes を導入してからいつの間にか一年経ったので、 ログを集計してみました。 縦軸は対数目盛にしてあります。 グラフの画像は procmail のログを python で抽出し、 PostScript 形式で出力して作りました。

unsure (判定できなかったもの) はこのところ 0.5% 前後と好成績。 日に一件くらいまで納まって来てます。 実用上無視できるレベルです。

それにしても、最近はスパムが 50% 越えてます。 仮にフィルタリングしないとすると大変です。 スパム送信者は回線コストを半分負担してほしい気持ち。 どういう理由か CO2 排出規制に消極的な御国からのメールが多いようです。



日本語メールだけ集計してみました。 残念ながらわが国も、そろそろ、その仲間入りしそうですね。 aug が赤い字になっている処は SpamBayes を 日本語対応 にした月を示してます。 その効果があったのか微妙です。 ただ八月を境にバラツキが減ってるように見えます。 気持ち効果ありと思いますが、それは贔屓目でしょうか? > 識者殿


29 September 2006

みんパイ

ming-0.3.0 + ming-py-0.3.0 + patch
Python  

「みんPy」 と云っても 某ベストセラー本 のことではありませんよ ;-p)

ming-py-0.3.0パッチ をあてました。 昨日の C++ コード を python で書き直したもの で試したところ、 SWF (FLASH) ファイル はできました。

# vim: set fileencoding=utf-8 enc=utf-8 :
from ming import *

movie = SWFMovie()
movie.setDimension(640, 480)

# 写真
photo = SWFBitmap('machi2006-02r.jpg')
movie.add(photo)

# タイトル
font = SWFFont('Mincho.fdb')
text = SWFText()
text.setFont(font)
text.setColor(0x00, 0x00, 0x00, 0xff)
text.setHeight(30)
text.addUTF8String("祭り唄")
item = movie.add(text)
item.moveTo(10, 30)

# サウンド
opt = SWF_SOUND_ADPCM_COMPRESSED | SWF_SOUND_16BITS
sound = SWFSound('machi-05k.adpcm', opt)
movie.startSound(sound);

movie.save('sample.swf')


フォントファイルは ttf から fdb タイプに変換しました。 ttf→fft 変換は本家から ttf2fft を持って来て make したものを使います。 makefdb は ming に付属しています。

$ ttf2fft -e 0 -o Mincho.fft /usr/X11R6/lib/X11/fonts/TrueType/sazanami-mincho.ttf
$ /usr/bin/makefdb Mincho.fft
$ mv Sazanami\ Mincho.fdb Mincho.fdb

サウンドファイルは wav 形式でも構いませんが、 ADPCM 形式で圧縮すればかなり小さくなります。

$ /usr/bin/raw2adpcm sample.wav sample.adpcm 1 0

SWFSound に与えるフラグセットは試行錯誤が必要です。 確かな情報はソースコードを見るしかなさそうです。 諸々のファイルは ここ に置きました。

参考サイト

14 August 2007

棋譜ブラウザ for Win

PyShogi 0.5.3 released
Python  

余ったマシンに Win2K をインストール。 py2exe を使い、特に問題なく exe ファイルを作成できた。 これで Python や VC++ が入って無い環境でも棋譜ブラウザ zbrowser は使えることが分かりました。 それよりも Linux 環境でこしらえた GUI アプリケーションが、 そのまま遜色無く動作したことに感激してます。 ありがたいことです。

もし試すなら ここから PyShogi-0.5.x.lzh の最新版をダウンロードし解凍してください。 zbrowser.exe をクリックするだけで左のような画面が現れるはずです。


と言ってはみたものの、 うちには他に win マシンが無いのでちゃんとしたテストはしてません。 もし MSVCR71.DLL などのランタイムライブラリが無いよと怒られたら、 どこぞからコピーして持って来ないといけないかもしれません。 Google あたりで探せば見つかると思います。

参考までに今回作成した setup.py のコードは以下の通りです。

#!/usr/bin/env python
from distutils.core import setup
from pyshogi import __project__, __version__
import py2exe
import glob

setup(
    #windows = ['zbrowser.py'],
    windows = [{'script':'zbrowser.py', 'icon_resources': [(1,'zbrowser.ico')]}],
    zipfile = None,
    name=__project__,
    version=__version__,
    description='Python Shogi Tools',
    author='Shu KONNO',
    author_email='owa@bg.wakwak.com',
    url='http://owa.as.wakwak.ne.jp/',
    scripts=['zbrowser.py'],
    packages=[
        'pyshogi',
        'pyshogi.Board',
        'pyshogi.Frame',
        'pyshogi.MiscFormats',
        'pyshogi.SimpleShogi',
    ],
    package_dir={
        'pyshogi':'pyshogi',
        'pyshogi.Board':'pyshogi/Board',
        'pyshogi.Frame':'pyshogi/Frame',
        'pyshogi.MiscFormats':'pyshogi/MiscFormats',
        'pyshogi.SimpleShogi':'pyshogi/SimpleShogi',
    },
    data_files=[
        ('pyshogi', ['pyshogi/bookmark.txt']),
        ('pyshogi/picts', glob.glob('pyshogi\\picts\\*.jpeg')),
        ('pyshogi/picts/boardset', glob.glob('pyshogi\\picts\\boardset\\*.jpg')),
        ('pyshogi/picts/boardset', glob.glob('pyshogi\\picts\\boardset\\*.png')),
        ('pyshogi/picts/boardset', glob.glob('pyshogi\\picts\\boardset\\*.gif')),
        ('pyshogi/picts/boardset', glob.glob('pyshogi\\picts\\boardset\\README.*')),
        ('pyshogi/picts/boardset/t-31-27-plane',
            glob.glob('pyshogi\\picts\\boardset\\t-31-27-plane\\*.png')),
        ('pyshogi/picts/boardset/t-31-27-tiger',
            glob.glob('pyshogi\\picts\\boardset\\t-31-27-tiger\\*.png')),
        ('pyshogi/picts/icons', glob.glob('pyshogi\\picts\\icons\\*.xbm')),
        ('pyshogi/picts/icons', glob.glob('pyshogi\\picts\\icons\\*.gif')),
        ('pyshogi/fonts', glob.glob('pyshogi\\fonts\\*.ttf')),
        ('pyshogi/fonts', glob.glob('pyshogi\\fonts\\README*')),
        ('pyshogi/fonts', glob.glob('pyshogi\\fonts\\LICENSE*')),
        ('i18n/ja/LC_MESSAGES', ['i18n/ja/LC_MESSAGES/zbrowser.mo']),
        ('i18n/en/LC_MESSAGES', ['i18n/en/LC_MESSAGES/zbrowser.mo']),
        ('doc', ['CHANGES', 'LICENSE', 'README']),
    ]
)

exe ファイルを作るには、以下のコマンドを実行します。

> python setup.py py2exe

参考サイト

04 December 2007

PythonからC++クラスを呼び出す

Python  

SIP を使い C++ クラスを Python から呼び出してみました。 他にも boostSWIG などあるらしいけど、こいつは軽快。良いかも。

たとえばこんな C++ クラス word.h があったとして、

class Word {
private:
    char* _word;
public:
    Word(const char*);
    const char* str() const { return _word; }
    void set(const char*);
    char* reverse() const;
};

sip を使いゴニョゴニョした後、

$ python
>>> from word import Word
>>> w=Word('abc')
>>> w.str()
'abc'
>>> w.reverse()
'cba'
>>> w.set('xyz')
>>> w.str()
'xyz'

こんなふうに Python からクラスとして扱えます。 "operator=" などサポートして無いものもあるらしいけど、スゴイ^^


作るものは C++ のヘッダに似てるけど word.sip

%Module word 0
class Word {
%TypeHeaderCode
#include 
%End
public:
    Word(const char*);
    const char* str() const;
    void set(const char*);
    char* reverse() const;
};
そして configure.py を適当に修正。
import os
import sipconfig

# The name of the SIP build file generated by SIP and used by the build
# system.
build_file = "word.sbf"

# Get the SIP configuration information.
config = sipconfig.Configuration()

# Run SIP to generate the code.
os.system(" ".join([config.sip_bin, "-c", ".", "-b", build_file, "word.sip"]))

# Create the Makefile.
makefile = sipconfig.SIPModuleMakefile(config, build_file)

# Add the library we are wrapping.  The name doesn't include any platform
# specific prefixes or extensions (e.g. the "lib" prefix on UNIX, or the
# ".dll" extension on Windows).
makefile.extra_libs = ["word"]

# Generate the Makefile itself.
makefile.generate()

あとはビルドすればできあがり。

$ g++ -fPIC -o word.o -c word.cpp
$ ar cr libword.a word.o
$ sip -c . word.sip
$ python configure.py
$ make

参考サイト

04 May 2008

PythonからC++クラスを呼び出す(2)

Python  

今回は Python の ctypes モジュールを使い C++ クラスを Python から呼び出してみました。 ctypes モジュールは python2.5 以降では標準で含まれるようです。 まずは C++ クラスのコンストラクタ、デストラクタ、メンバ関数の wrapper 関数を作り、 Python から呼び出してみました。

題材は昨今作成中の詰将棋プログラムです。 以下のサンプル出力では、 まず共有ライブラリ libcshogi.so をロードし、 次にコンストラクタに盤面情報を文字列で渡し、 最後に探索メソッドを呼び出し、解答を出力しています。 ctypes は使い易い。Python 標準実装と云うのも心強いし、 とりあえず決まりかな^^

$ python2.5
>>> import ctypes
>>> so=ctypes.CDLL("./libcshogi.so")
>>> cp=so.cshogi_create('K32S22S34L11P13P23P44~R2BG3S2N4L3Pe/P54b53p41~G/')
 9 8 7 6 5 4 3 2 1
|.|.|.|.|.|p|.|.|L|1 {R2,B,G3,S2,N4,L3,Pe}
|.|.|.|.|.|.|K|S|.|2
|.|.|.|.|b|.|.|P|P|3
|.|.|.|.|P|P|S|.|.|4
|.|.|.|.|.|.|.|.|.|5
|.|.|.|.|.|.|.|.|.|6
|.|.|.|.|.|.|.|.|.|7
|.|.|.|.|.|.|.|.|.|8
|.|.|.|.|.|.|.|.|.|9 {G}

>>> so.cshogi_solve(cp, 7)
G33 K2132 b3153 S3122 p3141 K3121 S32
G33 K2132 b3153 S3122 p3141 K1221 S21


以下の説明では話を簡単にするため、次のような C++ クラス CShogi を考えます。 (実際のファイルは CShogi.h と CShogi.cpp)

#include <cstring>
class CShogi {
private:
    char buf[512];
public:
    CShogi() {
        printf("CShogi:: (new)\n");
    }
    ~CShogi() {
        printf("CShogi:: (del)\n");
    }
    void puts(const char* p) {
        printf("CShogi::puts (%s)\n", p);
        strcpy(buf, p);
    }
    const char* gets() const {
        printf("CShogi::gets (%s)\n", buf);
        return buf;
    }
};

まず wrapper 関数を作ります。ソース cshogi.cpp は以下の通り。

#include "cshogi.h"
#include "CShogi.h"
void* cshogi_create() {
    return (void*) new CShogi;
}
void cshogi_delete(void* p) {
    delete (CShogi*)p;
}
void cshogi_puts(void* p, const char* s) {
    ((CShogi*)p)->puts(s);
}
const char* cshogi_gets(void* p) {
    return ((CShogi*)p)->gets();
}

ヘッダファイル cshogi.h は C からも呼び出せる形式にします。 次のようになります。

#ifdef __cplusplus
extern "C" {
#endif
    void* cshogi_create(void);
    void cshogi_delete(void*);
    void cshogi_puts(void*, const char*);
    const char* cshogi_gets(void*);
#ifdef __cplusplus
}
#endif

次に共有ライブラリを作ります。 ビルドが正常終了したなら libcshogi.so がカレントディレクトリに出来てるはずです。

$ g++ -g -Wall -fPIC -o CShogi.o -c CShogi.cpp
$ g++ -g -Wall -fPIC -o cshogi.o -c cshogi.cpp
$ g++ -shared CShogi.o cshogi.o -o libcshogi.so

さて、Python から呼び出してみましょう。

$ python2.5
>>> import ctypes
>>> so = ctypes.CDLL("./libcshogi.so")
>>> cp = so.cshogi_create()
CShogi:: (new)
>>> so.cshogi_puts(cp, 'abc')
CShogi::puts (abc)
>>> so.cshogi_gets(cp)
>>> so.cshogi_gets.restype = ctypes.c_char_p
>>> so.cshogi_gets(cp)
CShogi::gets (abc)
'abc'
>>> so.cshogi_delete(cp)
CShogi:: del

最後に Python のクラスモジュール CShogi.py を作ります。 関数のプロトタイプ宣言が追加されています。 __del__ メソッドにはバッドノウハウを追加。

#! /usr/bin/python2.5
import ctypes
from ctypes import c_void_p, c_char_p
so=ctypes.CDLL("./libcshogi.so")

class CShogi(object):
    def __init__(self):
        so.cshogi_create.restype = c_void_p
        self.v = so.cshogi_create()
    def __del__(self, so=so):
        so.cshogi_delete.argtypes = [c_void_p]
        so.cshogi_delete(self.v)
    def puts(self, s):
        so.cshogi_puts.argtypes = [c_void_p, c_char_p]
        so.cshogi_puts(self.v, s)
    def gets(self):
        so.cshogi_gets.argtypes = [c_void_p]
        so.cshogi_gets.restype = c_char_p
        return so.cshogi_gets(self.v)

if __name__ == '__main__':
    ob = CShogi()
    ob.puts('abc')
    a = ob.gets()
    ob.puts('xyz')
    x = ob.gets()
    print 'a=', a, 'len=', len(a), 'type=', type(a)
    print 'x=', x, 'len=', len(x), 'type=', type(x)

これを実行した出力は以下の通りです。

$ python2.5 CShogi.py
CShogi:: (new)
CShogi::puts (abc)
CShogi::gets (abc)
CShogi::puts (xyz)
CShogi::gets (xyz)
a= abc len= 3 type= <type 'str'>
x= xyz len= 3 type= <type 'str'>
CShogi:: (del)

参考サイト