Pythonで新しいシステムのプロトタイプを作成しています。機能はほとんど数値です。
重要な要件は、個々のユーザー実装からNumpyなどのジェネリックライブラリまで、さまざまな線形代数バックエンドを使用できることです。線形代数の実装(つまり、バックエンド)は、インターフェイスから独立している必要があります。
私の最初のアーキテクチャの試みは次のとおりです。
(1)システムインターフェースを定義する
>>> v1 = Vector([1,2,3])
>>> v2 = Vector([4,5,6])
>>> print v1 * v2
>>> # prints "Vector([4, 10, 18])"
(2)バックエンドとは独立してそのインターフェースを使用できるようにするコードを実装します
# this example uses numpy as the back-end, but I mean
# to do this for a general back-end
import numpy
def numpy_array(*args): # creates a numpy array from the arguments
return numpy.array(*args)
class VectorBase(type):
def __init__(cls, name, bases, attrs):
engine = attrs.pop("engine", None)
if not engine:
raise RuntimeError("you need to specify an engine")
# this implementation would change depending on `engine`
def new(cls, *args):
return numpy_array(*args)
setattr(cls, "new", classmethod(new))
class Vector(object):
__metaclass__ = VectorBase
# I could change this at run time
# and offer alternative back-ends
engine = "numpy"
@classmethod
def create(cls, v):
nv = cls()
nv._v = v
return nv
def __init__(self, *args):
self._v = None
if args:
self._v = self.new(*args)
def __repr__(self):
l = [item for item in self._v]
return "Vector(%s)" % repr(l)
def __mul__(self, other):
try:
return Vector.create(self._v * other._v)
except AttributeError:
return Vector.create(self._v * other)
def __rmul__(self, other):
return self.__mul__(other)
この簡単な例は次のように機能します。Vector
クラスは、バックエンド(numpy.ndarray
例では)によって作成されたベクターインスタンスへの参照を保持します。すべての算術呼び出しはインターフェースによって実装されますが、それらの評価はバックエンドに延期されます。
実際には、インターフェイスはすべての適切な演算子をオーバーロードし、バックエンドに依存します(例では__mul__
とのみが表示__rmul__
されますが、すべての操作で同じことが行われることを確認できます)。
カスタマイズ性と引き換えに、パフォーマンスをいくらか失うことをいとわない。私の例は機能しますが、それは正しく感じられません-非常に多くのコンストラクター呼び出しでバックエンドを壊してしまいます!これは別のmetaclass
実装を要求し、より良い呼び出し延期を可能にします。
では、この機能を実装することをどのように推奨しますか?Vector
システムのすべてのインスタンスを均一に保ち、線形代数のバックエンドから独立させることの重要性を強調する必要があります。