__metaclass__2 メソッドの置き換え
問題
実行に時間のかかる処理longlongtime_processを持つクラスAがある感じで。
このAを継承しているクラス、Aa,Abがある。
でも、longlongtime_processは時間がかかるので、テストの際には、それとは違うshorttime_processに変えたい。
以下のような階層関係のクラス。
# 階層構造 A<have longlongtime_process> |__ Aa |__ Ab # test ではAa,Abでshorttime_processを使いたい。 # longlongtime_processをshorttime_processに置き換えたい。 A -> Aa -> AaProxy<have shortime_process> A -> Ab -> AbProxy<have shortime_process> というクラスを作る必要がありそう。
このとき、shorttime_processでは、Aの持っている状態を利用したい。
でも、shorttime_processをひとつずつ追加したくない。(面倒)
こんな感じの実行結果にしたい
Aa: longlongtime_process <x>message y Ab: longlongtime_process <x>message y z Aa: Proxy longlongtime_process(short time)<x>message<x> y Ab: Proxy longlongtime_process(short time)<x>message<x> y z
コード
__metaclass__を使ってできたのでコードを載せる。
# -*- coding:utf-8 -*- class A(object): def __init__(self, x): self.x = x def longlongtime_process(self, message): #他との通信とか。時間のかかる処理。 return "longlongtime_process "+self.x + message def g(self, result): raise Exception(result) def run(self, message): result = self.longlongtime_process(message) return self.g(result) ## longlongtime_processを書き換えたい。 class Aa(A): def __init__(self, x, y): super(Aa, self).__init__(x) self.y = y def g(self, result): text = "\t".join(["Aa:", result, self.y]) print(text) class Ab(A): def __init__(self, x, y, z): super(Ab, self).__init__(x) self.y = y self.z = z def g(self, result): text = "\t".join(["Ab:", result, self.y, self.z]) print(text) x, y, z = "<x>", "y", "z" Aa(x, y).run("message") Ab(x, y, z).run("message") ## idea class AaProxy(Aa): def __init__(self, *args, **kw): super(AaProxy, self).__init__(*args, **kw) def longlongtime_process(self, message): return "Proxy shorttime_process..." + self.x + message + self.x AaProxy(x, y).run("message") class ProxyMeta(type): def __init__(cls, name, bases, attrs): def shorttime_process(self, message): return "Proxy shorttime_process..." + self.x + message + self.x setattr(cls, "longlongtime_process", shorttime_process) class AbProxy(Ab): __metaclass__ = ProxyMeta AbProxy(x, y, z).run("message")
クラスを継承したときに__init__を定義しないと、自動で親のクラスの__init__を呼んでくれる?
追記
多重継承で十分かも知れない
class A(object): def __init__(self, x): self.x = x class AB(A): def __init__(self, x, y): super(AB, self).__init__(x) self.y = y class UseXMixin(object): def use_x(self): print self.x class ABC(AB, UseXMixin): pass ABC(10, 20).use_x() # > 10
UseXMixinを継承しておけばメソッドが定義されるし、ABCのインスタンス変数を見るのでこれで大丈夫。
上の例に対応させると
class ShoftTimeProcessMixin(object): def longlongtime_process(self, message): return "Proxy shorttime_process..." + self.x + message + self.x class AbProxy(ShoftTimeProcessMixin, Ab): pass AbProxy(x, y, z).run("message") # Ab: Proxy shorttime_process...<x>message<x> y z
ただ、継承の順序を変えて(Ab,ShortTimeProcessMixin)だとうまく機能しない。
順序依存なので怖いかも。