やや柔軟なFactory

apply()とgetattr()を使って、Factory作るための簡単な実験を行ってみた。
Hoge classと、Fuga classを動的にinstance化して、prn()メソッドを叩く実験を行ってみたので、作り方と結果を以下に記載する。

準備

Hogeクラスと、Fugaクラスを作成。両クラス名を持つリストを用意。
このリストを利用して、クラスを動的に生成する。

class Hoge():
    def prn(self):
        print self.__class__.__name__

class Fuga():
    def prn(self):
        print self.__class__.__name__

klasses = [Hoge, Fuga]

apply()でつくる場合

"初めてのpython(第3版)"にも載っている例(に近い物)。

コード
    for klass in klasses:
        kls = apply(klass) # class名で直にいける,klsにはinstanceが入る
        kls.prn()
実行結果
Hoge
Fuga

getattr()でつくる場合

インポート先も動的に指定してクラスを取得し、instance化したいときにいけるかも。

コード
    import __main__
    klasses = [Hoge, Fuga]
    for klass in klasses:
       kls = getattr(__main__, klass.__name__)() # クラス名はstringで呼ばないといけない(※)
       kls.prn()
実行結果
Hoge
Fuga

余談

※試みに、以下のようにしたが、これだと動作しなかった

コード
    import __main__
    klasses = [Hoge, Fuga]
    for klass in klasses:
#       kls = getattr(__main__, klass.__name__)                                                                                                                                
#       kls().prn()                                                                                                                                                            
        kls = getattr(__main__, klass.__init__)
        kls.prn()
実行結果
$ ./create_meta_object.py                          |
Traceback (most recent call last):                                                     
  File "./create_meta_object.py", line 30, in <module>
    kls = getattr(__main__, klass.__init__)           
AttributeError: class Hoge has no attribute '__init__'

なぜ、(constructorである)'__init__'が無いと怒られるのかが良く理解できていない。
結果を受けて、試みに、def __init__(self):pass をつけてみたが、別のエラーが出て本日は断念。分かったら後日報告したい。

追記(2012/03/07 Mi.)

(当たり前だけど)もっと単純にこれで良かったのか...。
しょうもないところで時間かけてしまったorz

コード
    klasses = [Hoge, Fuga]
    for klass in klasses:
	kls = klass()
	kls.prn()
実行結果
$ ./create_meta_object.py
Hoge
Fuga

Factoryへの応用

Factoryの中で指定されたパラメータに応じて生成するクラスを動的に切り替える時には、klassesでリストを使用した代わりに、辞書を使用する、や、あるdir配下のmoduleから自動でクラス名を取得して利用する等、色々応用が効きそうです。
直接クラス名を指定せずに、instance化出来るのが簡単にできて使い勝手が良さそうです。
(調べるのは時間かかったけど)

初めてのPython 第3版

初めてのPython 第3版