[Python][Twisted] twisted.internet.reactorが使えるようになるまで

環境

この記事の内容は、Ubuntu Linux 6.10, Python 2.4.4c6, Twisted 2.4.0で確認しました。

疑問点

Twistedを理解しようとして、twisted.internet.reactorはどんなモジュールだろうかと思い、/usr/lib/python2.4/site-packages/twisted/internet/reactor.pyを読んでみたところ、以下の記述しかなく、クラスや関数は定義されていませんでした。それどころか、twisted.internet.reactorモジュールをシステムから削除さえしています。

# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
# See LICENSE for details.

"""
See twisted.internet.interfaces.IReactor*.
"""
import sys
del sys.modules['twisted.internet.reactor']
#from twisted.python import log
#log.msg("Installing SelectReactor, since unspecified.")
from twisted.internet import selectreactor
selectreactor.install()

そこで、実際にtwisted.internet.reactorという名前のモジュールが使えるようになるまでの流れを追いました。

結論

twisted.internet.reactorモジュールというのは、実はtwisted.internet.SelectReactorオブジェクトのことです。

詳細

/usr/lib/python2.4/site-packages/twisted/internet/reactor.pyの最後に、

from twisted.internet import selectreactor
selectreactor.install()

とあるので、次に/usr/lib/python2.4/site-packages/twisted/internet/selectreactor.pyファイルの中にあるinstall関数を読んでみます。

def install():
    """Configure the twisted mainloop to be run using the select() reactor.
    """
    reactor = SelectReactor()
    from twisted.internet.main import installReactor
    installReactor(reactor)

ここでは、SelectReactorオブジェクトを作成し、これをtwisted.internet.main.installReactor関数に渡しています。ここで、SelectReactorクラスは、同じファイルで以下のように説明されています。

class SelectReactor(posixbase.PosixReactorBase):
    """A select() based reactor - runs on all POSIX platforms and on Win32.
    """

さて、/usr/lib/python2.4/site-packages/twisted/internet/main.pyのinstallReactor関数は、以下のようになっています。

def installReactor(reactor):
    # this stuff should be common to all reactors.
    import twisted.internet
    import sys
    assert not sys.modules.has_key('twisted.internet.reactor'), \
           "reactor already installed"
    twisted.internet.reactor = reactor
    sys.modules['twisted.internet.reactor'] = reactor

この関数のreactor引数は、先ほどみた通り、twisted.internet.selectreactor.SelectReactorオブジェクトです。それを、installReactor関数では、

    sys.modules['twisted.internet.reactor'] = reactor

で、モジュールとして登録しています。すなわち、twisted.internet.reactorモジュールの関数を呼び出す、というのは実は、twisted.internet.selectreactor.SelectReactorオブジェクトのメソッドを呼び出しているということになるのです。

実際に確認しています。

>>> from twisted.internet import reactor
>>> type(reactor)
<class 'twisted.internet.selectreactor.SelectReactor'>
>>> type(reactor.run)
<type 'instancemethod'>

このように、twisted.internet.reactor.runは、'function'ではなく、'instancemethod'となっています。

なぜTwistedがこのような手順を踏んでいるのかは不明ですが(素直にtwisted.internet.selectedreactor.SelectedReactorクラスを直接インスタンス化してはいけないんでしょうか...)、このようにモジュールとオブジェクトを入れ換えるということができるのは、Pythonの動的プログラミングだからこその手法かと思います。