4

Functionそのインスタンスが 1 つの引数を取る callable であるclassがあるとします。これらのクラスの点ごとの演算を簡単な方法で定義しました。これが私のコードの簡略化されたバージョンです(実際には and でより複雑な動作をし__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

Function同じ算術式で aとインスタンスの両方が表示される場合、メソッドを使用するように暗黙的に変換しFunctionalたいと考えています。FunctionFunctionalFunctional.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

1つのオプションは、Functionクラス内のすべての演算子が任意の値を受け入れるようにすることです。これは、関数自体でない場合、基になる関数の結果に適用されます。たとえば、が関数であるf / 5場合にallowを拡張するには、実装を変更するだけです。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)

オプションで、それが正常であることを確認するためにいくつかの型チェックを行うことができます(そして、後でではなく早期にエラーを発生させます)が、それがなくても機能します。

于 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 に答える