4

假设我有 class 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

换句话说,每当我在实例v旁边的算术表达式中看到一个数字对象时Function,我都想转换vFunction(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

当我在同一个算术表达式中同时看到 aFunction和一个实例时,我想隐式转换为using方法。FunctionalFunctionFunctionalFunctional.from_function

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

  • 功能性
  • 功能
  • 还要别的吗

而且我想隐式转换为在给定算术表达式中看到的这个层次结构中的最高类型。

4

3 回答 3

2

对于所有运营商来说,这样的事情都会很好地工作:

def __truediv__(self, other):
  if callable(other):
      return Function(lambda x:self(x)/other(x))
  else:
      return Function(lambda x:self(x)/other)
于 2012-12-03T08:32:09.113 回答
1

一种选择是让Function类中的所有运算符都接受任意值,如果它们本身不是函数,这些值将应用于底层函数的结果。例如,要扩展 allow f / 5,whenf是一个函数,只需修改__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)

您可以选择进行一些类型检查以确保它是理智的(并尽早而不是稍后引发错误),但没有它它也可以工作。

于 2012-12-03T08:32:45.600 回答
0

在阅读了评论和其他答案后,我尝试了这种方法。我发布它是为了征求意见。我喜欢我可以一口气处理这两种情况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)
于 2012-12-03T09:25:50.007 回答