DDDのリポジトリパターンとコンテキストマップを利用するにあたって、インスタンスに対して動的に振る舞いを付与したくなったので、Python で DCI (Data Context Interaction) を実現する方法について調べてみました。
Roles パッケージを使う
DCI in Pythonスレから産まれたらしい Python の DCI パッケージ
わりと古くて人気もなさそうだけど、よくできている。
class Person(object):
def __init__(self, name):
self.name = name
from roles import RoleType
class Carpenter(object):
__metaclass__ = RoleType
def chop(self):
return "chop, chop"
のように Person, Carpenter を定義すると、
>>> person = Person("John")
>>> Carpenter(person)
<Person+Carpenter object at 0x...>
Person インスタンスに Carpenter の振る舞いを付与できる。
Dynamic Mixin
Mixin クラスの属性をインスタンスに動的に追加する関数を実装。
import types
def mixin(instance, mixin_class):
"""Dynamic mixin of methods into instance - works only for new style classes"""
for name in mixin_class.__dict__:
if name.startswith('__') and name.endswith('__') \
or not type(mixin_class.__dict__[name])==types.FunctionType:
continue
instance.__dict__[name]=mixin_class.__dict__[name].__get__(instance)
使い方
class Person(object):
def __init__(self, name):
self.name = name
class CarpenterMixin(object):
def chop(self):
return "chop, chop"
と定義されていたとして、
>>> person = Person("John")
>>> mixin(person, CarpenterMixin)
>>> person.chop()
'chop, chop'
わりと手軽。
Dynamic Mixin (2)
instance のクラスの継承ツリーを動的に書き換えるアグレッシブな方法。
説明は省略。リンク先を見てください。
その他
インスタンスそのものに振る舞いを付与するのを諦めて、Delegation で実現するのもありかと思います。
参考情報
以下のページを大いに参考にさせて頂きました。