pythonのソースコードを読むコツのようなもの

2007/09/20 追記。以下で色々頑張ってるようなこと全部IPythonで出来るみたい...orz
まだまだ駆け出しなりに連日試行錯誤してわかってきたことがあるので書いておく。
これからpythonはじめる人とかの参考になればうれしい。
それは違うだろ?っていうpythonistaの方の突込みがあるとさらにうれしい。

道具重要!!

  • pythonインタプリタ
    • これがないと始まらない。
    • どうでもいいけどrubyirbみたいに固有名詞は定義されてないのかな。
  • pydoc
  • inspect
    • これの存在しってから劇的にコードの読み方が変わった。
  • pdb
    • まだあんまり使ってないけど一応。

pythonインタプリタ

rlcompleterとreadlineが使えるようにしておくのがお勧め。

import rlcompleter, readline

でエラーでないならOK。やり方は以前書いたので省略。
IPythonがお勧めらしいけど結局使ってない...。

pydoc

モジュールや関数、クラス、インスタンスメソッドなどのサマリを手っ取り早く参照したい時に使うようにするつもり。
ちょっと調べたいだけならターミナル上で

% pydoc sys

もしくはpythonインタプリタ上で

>>> import sys
>>> help(sys)

するのが簡単で楽。小中規模のソースコードの全体像を俯瞰してみたい場合はpydocがいいと思う。

標準モジュールなどはhttp://pydoc.org/にあった。
使い方はhttp://pydoc.org/2.4.1/pydoc.html
日本語ならhttp://www.python.jp/doc/2.4/lib/module-pydoc.html

pydocをまとめて手っ取り早く生成する方法

例えば以下のようにすると、pythonインタプリタを起動したディレクトリ配下に生成される。
djangoなどでも同様の方法で生成可能。

>>> import pydoc
>>> pydoc.writedocs('/usr/lib/python2.4/')

inspect

便利すぎる。まじで。もはやこれなしで過ごせなくなりつつある。
これはpython本気で勉強しだして以来最大の収穫といっても過言じゃないかもしれない。
個人的にはこれを知ったおかげで世界が変わった。
オンラインドキュメント最初にちゃんと読めという話はおいといて...
何がすごいってpythonインタプリタ上からピンポイントで各種ライブラリの実装を取得できるのが個人的に便利すぎる。

実行例
  • django.db.models.base.Model#__eq__の実装を調べる
  • 上記実装で呼んでいるdjango.db.models.base.Model#_get_pk_val()の実装を調べる
  • django.db.models.base.Model#_get_pk_val()がどのファイルに定義されているか調べる
  • django.db.models.base.Model#_get_pk_val()が何行目に定義されているか調べる

上記を調べたい場合に以下のようにすると簡単に調べられる。

>>> import inspect
>>> from django.db.models.base import Model
>>> print inspect.getsource(Model.__eq__)
    def __eq__(self, other):
        return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()
>>> print inspect.getsource(Model._get_pk_val)
    def _get_pk_val(self):
        return getattr(self, self._meta.pk.attname)
>>> print inspect.getfile(Model._get_pk_val)
/usr/lib/python2.4/site-packages/django/db/models/base.py
>>> array = inspect.getsourcelines(Model._get_pk_val)
>>> print array[1]
83

さらに補完とはいえ毎回似たようなのを打つのが面倒なら全てがオブジェクトなのを利用して

>>> igf = inspect.getfile
>>> print igf(Model._get_pk_val)
/usr/lib/python2.4/site-packages/django/db/models/base.py

とか出来る。んでこの辺りの初期設定を以前pythonインタプリタでのメソッド名の補完で書いた~/.pythonrc.pyに追記してみた。

import rlcompleter, readline
readline.parse_and_bind('tab: complete')

import inspect
igd = inspect.getdoc
igs = inspect.getsource
igf = inspect.getfile
igsl = inspect.getsourcelines

で、試してみると

>>> ig
igd   igf   igs   igsl
>>> igd(igf)
'Work out which source or compiled file an object was defined in.'
>>> print igs(igf)
def getfile(object):
    """Work out which source or compiled file an object was defined in."""
    if ismodule(object):
...中略

うん、これでちょっとははかどるようになるかなぁ。強いて不満点を上げるとすればソースコードハイライトがないことくらいかな。
まぁがっつり読むときはvimで読むからいいか。

pdb

正直まだしっかり使ってないけれど実際に実行しながらソースコード読むときに重宝しそう。詳細はたぶん書かない。
http://0xcc.net/blog/archives/000162.html
ここで色々書いてあるのでこれを後で読んで試す(たぶん)