LLSpirits の Language Update で 柴田さん が、「Python は 2.4 → 2.5 → 2.6 → 3.0 → 3.1 って追いかけていけばいいよ」って話されていたのを思い出した。(参考)

で、今日、Python 2.6 のドキュメント(英語) が出てるのに気づいた。

What’s New in Python 2.6 をざっと眺めてみたら、

  • 2.6 でも今までの 2.5 のコードはちゃんと動く。
  • __complex__() が使える
  • except TypeError as exc. ←なにこれ。
  • reduce() の代わりに functools.reduce() が使える
  • -3 オプションをつけて実行すると、 3.0 に移行したら使えなくなるところを警告してくれる
  • ドキュメントが reStrucuturedText で書かれるようになった。
  • ‘with’ statement が使える
  • その他 'with' statement を使ったいろいろ

とか、他にもいっぱい書いてあるけれど、もう眠すぎるから寝る。見つけたタイミングが悪すぎた。後でちゃんと読もう。あ、あと、ここもあわせて読みたい。

2008.01.22 Tue l Python l COM(1) TB(0) l top ▲

Do you use a python code analyzer? という記事を見て、Pylint / PyChecker / Pyflakes / PythonTidy というものがあるのを知った。

こういうのを使えば、くだらないバグがあったせいで最初から実行し直したりしなくて済むってことか…。もっと早く知りたかった……。

2008.01.18 Fri l Python l COM(0) TB(0) l top ▲

先日、Python の xmpppy というパッケージを使えば、簡単に bot が作れるよーという記事を書いたけれど、そのサーバの方はどうなっているのかと調べてみたら、やっぱりありました。

Jabberサーバーをクラスタリングしてみました。 - DSAS開発者の部屋

なるほど…。xmpppy + Python の向こう側にこのシステムがあるおかげで、しかもそのサーバにタダでアクセスさせてもらえているおかげで、私でも簡単に bot を作って遊べるんですね。ありがとうございます!

そういえば、これは前から思っていたことなんだけど、オープンソースのすごいソフトウェアや、あるいは気前がいいすごい人が運営しているサービスを、私はタダで使わせてもらっている。なのに、そんなすばらしい社会に恩返しも何もできないのは悔しい。もっと勉強しなきゃ!

2008.01.17 Thu l Python l COM(0) TB(0) l top ▲

っていうか作ったよ。っていう話。それから日本語の情報が全くなくて苦労したから、ここにメモっておくよっていう話。

xmpppy とは、 XMPP のプロトコルを Python から使うためのパッケージのこと。http://xmpppy.sourceforge.net/ に詳しく書いてある。

XMPP とは、 Jabber っていう会社が作った仕様がオープンなプロトコルのこと。チャットとかメールとか、メッセージを交換するために使うためのプロトコル。 SMTP が何かに置き換わるとしたら、たぶんこれに置き換わる。っていうか置き換わってほしい。 XMPP は、有名なところでは Google Talk とか Pidgin がサポートしている。つまり XMPP のプロトコルでしゃべる bot を作れば、その bot と Google Talk を使ってお話できる!!そのボットのアドレスを twitter に登録しておけば、 bot が twitter を使ってしゃべってくれる。まぁ twitter は API があるから、それを定期的に動かせば済むけどね。

XMPP の詳しい仕様はXMPP RFCsに全部書いてある。でも、チャットする bot を作るだけだったら、RFC3921を見れば、だいたい大丈夫。その bot を xmpppy を使って書くんだったら、このエントリを見るだけでだいたい大丈夫。

まず、このプロトコルは C/S になってるから、サーバを決める必要がある。Google にアカウントを作ってもいいし、www.jabber.jpで作っても OK。ちなみに jabber.jp を管理してくれているのは、あの有名な KLab 株式会社 さんです。ありがとう!

アカウントを作ったら、次は xmpppy をインストールしよう。xmpppy を使うには pydns も必要だから、先に pydns をインストールする。インストールはいつもの python setup.py install でやってくれる。

インストールしたら、さっそく bot のスクリプトを書く。

import xmpp, sys
user = 'ユーザ名' # @gmail.com, @jabber.jp
pwd   = 'パスワード'
cnx = xmpp.Client('ドメイン名', debug=[])
cnx.connect( server=('サーバ名',5222) )

def presenceCB(con, prs):
    """Called when a presence is recieved"""
    who = str(prs.getFrom())
    type = prs.getType()
    if type == None: type = 'available'

    # subscription request: 
    # - accept their subscription
    # - send request for subscription to their presence
    if type == 'subscribe':
        con.send(xmpp.protocol.Presence(to=who, typ='subscribed'))
        con.send(xmpp.protocol.Presence(to=who, typ='subscribe'))
        
    # unsubscription request: 
    # - accept their unsubscription
    # - send request for unsubscription to their presence
    elif type == 'unsubscribe':
        con.send(xmpp.protocol.Presence(to=who, typ='unsubscribed'))
        con.send(xmpp.protocol.Presence(to=who, typ='unsubscribe'))

def messageCB(con, mess):
     txt = mess.getBody()
     reply = mess.buildReply(txt)
     con.send(reply)

cnx.RegisterHandler("presence", presenceCB)
cnx.RegisterHandler("message", messageCB)
cnx.sendInitPresence()

while 1:
    try:
        cnx.Process(1)
    except:
        cnx.send(xmpp.protocol.Presence(typ="unavailable"))
        cnx.disconnect()
        sys.exit()

これがひな形。XMPP の RFC で MUST になっている部分は、これで満たしている(はず)。このスクリプトは、起動するとサーバに接続する。他のアカウントから話しかけられると、オウム返しする。スクリプトを止めるときは C-c する。

bot として使うためには、messageCB を適当な関数に置き換える。たとえば、 messageCB

from urllib import urlopen, quote_plus
from lxml import etree
import xmpp, re

rename = {"euc":"eucjp"}

def urlread(url):
    import re, codecs
    page = urlopen(url)
    charset = re.search("charset=(\w+)", page.info().getheader("Content-Type"))
    if charset:
        charset = charset.group(1)
        return codecs.getdecoder(charset)(urlopen(url).read())[0]
    else:
        parser = etree.HTMLParser(remove_comments=True, remove_blank_text=True)
        html_page = etree.parse(urlopen(url), parser)
        root = html_page.getroot()
        meta = root.xpath('.//meta[@http-equiv="Content-Type"]')
        charset = re.search("charset=(\w+)", meta[0].attrib["content"])
        if charset:
            charset = charset.group(1)
            if charset in rename.keys():
                charset = rename[charset]
                return codecs.getdecoder(charset)(urlopen(url).read())[0]
            else:
                return urlopen(url).read()

def extractDefinition(data):
    from StringIO import StringIO
    from lxml import etree
    parser = etree.HTMLParser()
    root = etree.parse(StringIO(data), parser).getroot()
    resultList = root.xpath('//table[@id="resultList"]/tr/td/ul/li')
    if len(resultList) < 10:
        resultList = resultList[:-1]
    else:
        resultList = resultList[:10]
    rtag = re.compile(u"<.*?>")
    rspace = re.compile(u"(\s)+")

    def rep(s):
        return rspace.sub(r"\1", rtag.sub(" ", s))
    res = []
    for e in resultList:
        res.append( rep( etree.tostring(e, encoding="utf-8")))
    res = " ".join(res)
    return res

def messageCB(conn, msg):
    try:
        txt  = msg.getBody()
        user  = msg.getFrom()
        if txt:
            txt = quote_plus(txt.encode("utf-8"))
            reply_msg = extractDefinition(urlread("http://eow.alc.co.jp/"+txt+"/UTF-8/"))
            if len(reply_msg) > 0:
                reply = msg.buildReply(reply_msg)
            else:
                reply = msg.buildReply('"'+txt+'"'+u'っていう単語は辞書にないよ。「もしかして機能」はまだ無いんだ。ごめんね。')
            conn.send(reply)
    except:
        pass

こんなスクリプトを書いたら、話しかけられた単語を英辞郎で検索して、ヒットした単語を上から 10 個を答える bot になる。

私はこのスクリプトにログ機能を持たせた bot を動かしている。これを使って自分専用の「最近調べた単語リスト」を作って、で、あとでログをcat logfile | sort | uniq して眺めてみて、忘れてしまった単語があったらもう1度調べる。ってことをしばらくやった後で単語の出現頻度を調べると、「よく出てくるんだけど覚えられない単語」が浮かび上がってくる、という仕組み。これをウェブサービスにしようと思ってたけれど、今は忙しくてそれどころじゃないのでメモだけ書いて公開しておく。2月になって落ち着いたら作る予定。 Enjoy!

2008.01.15 Tue l Python l COM(0) TB(0) l top ▲

Python のスクリプトをぶん回していたら、

*** glibc detected *** python: free(): invalid pointer: 0xb548aa60 ***
============== Backtrace =======
なんちゃらかんちゃら...

というエラーが出た。これって Python2.5 のバグ?ググったら同じエラーメッセージを見た人はいるみたいだけど、どうしたらいいのか不明。しかも今はなぜか python.org にアクセスできない。

追記:アクセスはできた。でもエラーの原因は不明。

2007.12.18 Tue l Python l COM(0) TB(0) l top ▲