状態を持ったmixinを作りたいときの検証用のmixin
状態を持ったmixinを作りたいときがある。(self.fooに依存しているけれど、self.fooが定義されているかわからない)
困ったので__init__後に、self.fooが定義されているか調べるデコレータを書いてみた。
毎回検証処理が走っても無駄なだけなので、成功したら元の__init__に上書きされる。
こんな感じで使う。
@init_validate("x", "y") class Foo(object): def __init__(self): self.x = 10
self.x,self.yが利用できることを検証している。
Foo() #self.yが存在しないのでエラー
残念ながら、__init__後に追加されるself.fooについては検証できない。
コード
# -*- coding:utf-8 -*- def _need_check(title, target, needs): for k in needs: if not hasattr(target, k): raise NotImplementedError("%s: %s is not found" % (title, k)) def init_validate(*needs): """ 初回に__init__を呼んだ時に、指定したself.fooを持っているか調べる """ def _init_validate(klass): __init__ = getattr(klass, "__init__") def do_when_init(init_function): def _do_when_init(self, *args, **kw): init_function(self, *args, **kw) _need_check("instance val", self, needs) setattr(klass, "__init__", init_function) return _do_when_init setattr(klass, "__init__", do_when_init(__init__)) return klass return _init_validate def class_validate(*needs): """ こっちはクラス変数を見る """ def _class_validate(klass): _need_check("class val", klass, needs) return klass return _class_validate
Mixinで使いたい
元々、これを使いたいのはmixinを作るときだった。
mixin先のクラスでvalidateしたいself.fooを記述するより、mixinを定義した時に作った方が良い。
そういう風なmixinを作る。
class ValidateMixin(object): """ mixinクラスを渡した時、そのクラスのneedsというクラス変数に格納されているself.fooを調べる。 というvalidateを持ったMixin """ @classmethod def validate(cls, klass): klass = class_validate("needs")(klass) return init_validate(*cls.needs)(klass)
継承したmixinクラスにはcls.needsが必要。これを使ってmixinを利用したクラスのself.fooを調べる感じ。
ValidateMixinの使い方
class GreetingMixin(ValidateMixin): needs = ["name"] # mixinしたクラスではself.nameが使えること!! def greet(self): print "%s: hello" % self.name @GreetingMixin.validate # self.nameある? class Me(GreetingMixin): pass Me() # self.nameないので失敗する。 # NotImplementedError: instance val: name is not found
そんな感じ。