モジュールによるmixinの実現

Pythonでも実はRubyのmixinのようなことが可能である。

def mixin(template, mod_name):
    import new, sys
    m = new.module(mod_name)	
    m.__dict__.update(**template())
    sys.modules[mod_name] = m

def template():
    def foo(self):
        return 'foo'
    def bar(self, x):
        return x*10
    return locals()
	
class Foo(object):
    mixin(template, 'mod1')
    from mod1 import *

f = Foo()
print f.foo()
print f.bar(1)

# 実行結果
test.py:14: SyntaxWarning: import * only allowed at module level
  class Foo(object):
foo
10

mixin()関数に"(関数名, 関数オブジェクト)ペアの辞書"とモジュール名の2つを渡すと、指定したモジュール名でモジュールを登録してくれる。後はクラス定義の中で、"from モジュール名 import *"するだけ。


全て取り込むときにワーニングが出てしまう。全て取り込めないと不便なので後で回避方法考える。個別に取り込みたいときは、"from mod1 import foo,bar"のようにする。この場合ワーニングが出ない。


あと、"from mixin(template) import *"と書きたかったが、fromの後は構文に制限がありわざと2行に分けた。__import__()も調べたが良い方法が見つからなかった。


以下のようにクラス定義の属性に追加する方法もあるが、新スタイルクラスのFoo.__dict__はdictproxyでupdate()が使えないので1つずつsetattrする必要があるし、旧スタイルクラスは普通のdictであるが、どっちにしてもクラス定義の外で追加しないといけないので分かりづらい。

clas Foo:pass

Foo.__dict__.update(template())