No sé si esto es tanto un encadenamiento de funciones como un encadenamiento invocable , pero, dado que las funciones son invocables, supongo que no hay ningún daño. De cualquier manera, hay dos formas en las que puedo pensar en hacer esto:
Subclasificación inty definición __call__:
La primera forma sería con una intsubclase personalizada que define __call__cuál devuelve una nueva instancia de sí mismo con el valor actualizado:
class CustomInt(int):
def __call__(self, v):
return CustomInt(self + v)
La función addahora se puede definir para devolver una CustomIntinstancia, que, como un invocable que devuelve un valor actualizado de sí mismo, se puede llamar en sucesión:
>>> def add(v):
... return CustomInt(v)
>>> add(1)
1
>>> add(1)(2)
3
>>> add(1)(2)(3)(44)
50
Además, como una intsubclase, el valor devuelto conserva el comportamiento __repr__y __str__de ints. Sin embargo, para operaciones más complejas, debe definir otros dunders de manera apropiada .
Como señaló @Caridorc en un comentario, addtambién podría escribirse simplemente como:
add = CustomInt
Cambiar el nombre de la clase a en addlugar de CustomInttambién funciona de manera similar.
Definir un cierre, requiere una llamada adicional para generar valor:
La única otra forma en la que puedo pensar involucra una función anidada que requiere una llamada de argumento vacía adicional para devolver el resultado. Estoy sin usar nonlocaly optar por fijar los atributos de los objetos de función para que sea portable entre pitones:
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
Esto se devuelve continuamente a sí mismo ( _inner_adder) que, si valse proporciona a, lo incrementa ( _inner_adder += val) y si no, devuelve el valor tal como está. Como mencioné, requiere una ()llamada adicional para devolver el valor incrementado:
>>> add(1)(2)()
3
>>> add(1)(2)(3)()
6