これが呼び出し可能なチェーンと同じくらい関数チェーンであるかどうかはわかりませんが、関数は呼び出し可能であるため、害はないと思います。いずれにせよ、私がこれを行うことを考えることができる2つの方法があります:
サブクラス化int
と定義__call__
:
最初の方法は、更新された値でそれ自体の新しいインスタンスを返すものint
を定義するカスタムサブクラスを使用する__call__
ことです。
class CustomInt(int):
def __call__(self, v):
return CustomInt(self + v)
関数add
は、CustomInt
インスタンスを返すように定義できるようになりました。インスタンスは、それ自体の更新された値を返す呼び出し可能オブジェクトとして、連続して呼び出すことができます。
>>> def add(v):
... return CustomInt(v)
>>> add(1)
1
>>> add(1)(2)
3
>>> add(1)(2)(3)(44)
50
さらに、int
サブクラスとして、戻り値はsの__repr__
および__str__
動作を保持しますint
。ただし、より複雑な操作の場合は、他のダンダーを適切に定義する必要があります。
@Caridorcがコメントで述べたように、add
単純に次のように書くこともできます。
add = CustomInt
クラスの名前をadd
ではなくに変更してCustomInt
も、同様に機能します。
クロージャを定義し、値を生成するために追加の呼び出しが必要です。
私が考えることができる他の唯一の方法は、結果を返すために余分な空の引数呼び出しを必要とする入れ子関数を含みます。私は使用しておらずnonlocal
、Python間で移植できるようにするために、関数オブジェクトに属性をアタッチすることを選択しています。
def add(v):
def _inner_adder(val=None):
"""
if val is None we return _inner_adder.v
else we increment and return ourselves
"""
if val is None:
return _inner_adder.v
_inner_adder.v += val
return _inner_adder
_inner_adder.v = v
return _inner_adder
これは継続的にそれ自体(_inner_adder
)を返し、aval
が指定されている場合はインクリメント(_inner_adder += val
)し、指定されていない場合は値をそのまま返します。私が述べたように()
、インクリメントされた値を返すために追加の呼び出しが必要です。
>>> add(1)(2)()
3
>>> add(1)(2)(3)()
6