我正在用 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__
and __rmul__
,但您可以遵循每个操作都会执行相同的操作)。
我愿意牺牲一些性能来换取可定制性。即使我的示例有效,但感觉不对——我会用这么多构造函数调用来破坏后端!这需要一个不同的metaclass
实现,允许更好的调用延迟。
那么,你会如何建议我实现这个功能呢?我需要强调保持所有系统Vector
实例同质且独立于线性代数后端的重要性。