使用隐式类型转换实现逐点算术



假设我有一个类Function,它的实例是接受一个参数的可调用对象。我以直接的方式为这些类定义了逐点算术。这是我的代码的简化版本(实际上我在__init____call__中有更复杂的行为,但与这个问题无关):

class Function:
'''
>>> f = Function(lambda x : x**2)
>>> g = Function(lambda x : x + 4)
>>> h = f/g
>>> h(6)
3.6
'''
def __init__(self, func):
self.func = func
def __call__(self, value):
return self.func(value)
def __truediv__(self, other):
if isinstance(other, Function):
return Function(lambda x:self(x)/other(x))
else:
return NotImplemented
# ...

当我试图允许隐式类型转换时,我陷入了困境。例如,我希望能够写:

>>> f = Function(lambda x : x ** 2)
>>> g = f+1
>>> g(5)
26

换句话说,每当我在Function实例旁边的算术表达式中看到数值对象v时,我都希望将v转换为Function(lambda x : v)

此外,我希望为我的一些用户定义类型实现类似的行为(同样,每当我在具有Function对象的同一二进制算术表达式中看到它们时)。

虽然我当然可以用规则和反射二进制算术运算符的强力组合来编码这个逻辑,每个运算符都检查isinstance(v, numbers.Number)isinstance(v, MyUserDefinedType),但我觉得可能有一种更优雅的方法。

此外,如果我的设计还有其他可能的改进,请告诉我。(Function对象很少创建,但调用频率很高,因此性能值得关注。)

编辑:

为了解决@Eric的评论,我应该澄清一下,我有另一个用户定义的类Functional:

class Functional:
'''
>>> c = [1, 2, 3]
>>> f = Functional(lambda x : x + 1)
>>> f(c)
[2, 3, 4]
>>> g = Functional(lambda x : x ** 2)
>>> h = f + g
>>> h(c)
[3, 7, 13]
'''
def __init__(self, func):
self.func = func
@staticmethod
def from_function(self, function):
return Functional(function.func)
def __call__(self, container):
return type(container)(self.func(c) for c in container)
def __add__(self, other):
if isinstance(other, Functional):
return Functional(lambda x : self.func(x) + other.func(x))
else:
return NotImplemented

当我在同一算术表达式中看到FunctionFunctional实例时,我希望使用Functional.from_function方法将Function隐式转换为Functional

因此,隐式类型转换层次结构如下所示:

  • 功能
  • 功能
  • 还有别的吗

我想隐式转换为给定算术表达式中该层次结构中的最高类型。

像这样的东西对所有操作员来说都能很好地工作:

def __truediv__(self, other):
if callable(other):
return Function(lambda x:self(x)/other(x))
else:
return Function(lambda x:self(x)/other)

一个选项是使Function类中的所有运算符都接受任意值,如果它们本身不是函数,则这些值将应用于底层函数的结果。例如,要扩展allowf / 5,当f是一个函数时,只需修改__truediv__实现即可:

def __truediv__(self, other):
if isinstance(other, Function):
return Function(lambda x:self(x)/other(x))
else:
return Function(lambda x:self(x)/other)

您可以选择性地进行一些类型检查,以确保这是合理的(并尽早而不是稍后提出错误),但没有这一点就可以工作。

在阅读了评论和其他答案后,我尝试了这种方法。我发布它是为了征求反馈。我喜欢我可以同时处理FunctionFunctional,但我担心就性能而言可能非常昂贵:

class Function:
'''
>>> f = Function(lambda x : x**2)
>>> g = Function(lambda x : x + 4)
>>> h = f/g
>>> h(6)
3.6
>>> k = f + 1
>>> k(5)
26
>>> m = f + (lambda x : x + 1)
>>> m(5)
31
'''
def __init__(self, arg):
if isinstance(arg, Function):
self.func = arg.func
elif callable(arg):
self.func = arg
else:
self.func = lambda x : arg
def __call__(self, value):
return self.func(value)
def __truediv__(self, other):
return self.__class__(lambda x:Function(self)(x)/Function(other)(x))
def __rtruediv__(self, other):
return self.__class__(lambda x:Function(other)(x)/Function(self)(x))
def __add__(self, other):
return self.__class__(lambda x:Function(self)(x)+Function(other)(x))
def __radd__(self, other):
return self.__class__(lambda x:Function(other)(x)+Function(self)(x))
# ...

class Functional(Function):
'''
>>> c = [1, 2, 3]
>>> f = Functional(lambda x : x + 1)
>>> f(c)
[2, 3, 4]
>>> g = Functional(lambda x : x ** 2)
>>> h = f + g
>>> h(c)
[3, 7, 13]
'''
def __call__(self, container):
return type(container)(self.func(c) for c in container)

最新更新