Pythonで簡略化されたTerm Rewriting System(TRS)/ Symbolic Algebra Systemを実装する方法を試しています。 これは、クラスインスタンスのインスタンス化プロセス中に特定のケースでオペランドをインターセプトして変更できるようにすることが本当に好きです。 私が思いついた解決策は、典型的な( 'タイプ'タイプの)クラスオブジェクトの動作を変更するメタクラスを作成することでした。今、この、だから> F(A、B、C)Python:クラスインスタンスの初期化の前に渡された引数を変更する
class Flat(object):
"""
Use for associative Operations to expand nested
expressions of same Head: F(F(x,y),z) => F(x,y,z)
"""
__metaclass__ = Preprocess
@classmethod
def _preprocess_(cls, *operands, **kwargs):
head = []
for o in operands:
if isinstance(o, cls):
head += list(o.operands)
else:
head.append(o)
return tuple(head), kwargs
-
class Preprocess(type):
"""
Operation argument preprocessing Metaclass.
Classes using this Metaclass must implement the
_preprocess_(*operands, **kwargs)
classmethod.
"""
def __call__(cls, *operands, **kwargs):
pops, pargs = cls._preprocess_(*operands, **kwargs)
return super(Preprocess, cls).__call__(*pops, **pargs)
例の場合は、ネストされた操作F(F(a、b)は、c)を展開することであろう動作は継承によって実現することができます。
class Operation(object):
def __init__(self, *operands):
self.operands = operands
class F(Flat, Operation):
pass
これは、所望の動作につながる:
print F(F(1,2,3),4,5).operands
(1,2,3,4,5)
しかし、私はそのような前処理クラスをいくつか組み合わせて、自然クラスのmroに従ってオペランドを順次処理したいと思います。
class Orderless(object):
"""
Use for commutative Operations to bring into ordered, equivalent
form: F(*operands) => F(*sorted(operands))
"""
__metaclass__ = Preprocess
@classmethod
def _preprocess_(cls, *operands, **kwargs):
return sorted(operands), kwargs
これは望みどおりに機能していないようです。フラット・オーダーレス・オペレーション・タイプの定義
結果は、最初の前処理スーパークラスのみが「アクティブ」になります。
print G(G(3,2,1),-1,-3).operands
(3,2,1,-1,-3)
どのように私はすべての前処理クラス前処理メソッドは、クラスのインスタンス化の前に呼び出されていることを確認することができますか?
更新:
私は正式に起因する新しいstackoverflowのユーザーとしての私の状態にはまだ私の質問に答えるように見えることはできません。 だから、私はこれはおそらく、私が思い付くことができる最高のソリューションであると考えている:
class Preprocess(type):
"""
Abstract operation argument preprocessing class.
Subclasses must implement the
_preprocess_(*operands, **kwargs)
classmethod.
"""
def __call__(cls, *operands, **kwargs):
for cc in cls.__mro__:
if hasattr(cc, "_preprocess_"):
operands, kwargs = cc._preprocess_(*operands, **kwargs)
return super(Preprocess, cls).__call__(*operands, **kwargs)
私は問題は予想通りsuper(Preprocess, cls).__call__(*operands, **kwargs)
は、CLSのMROを横断していないということですね。
アロケータをオーバーライドして、ベースを調べるようにします。 –
うーん、どうしたらうまくいくの?プリプロセス.__ call__メソッドでclsオブジェクトの__bases__を印刷すると、(期待どおり) (、 __main __、 __main __。Operation '>) –
Nikolas
動的な型のオブジェクトを返す必要があります。だからこそあなたはアロケータでそれを行います。 –