Una de las principales ventajas de Python es su expresividad. La funcionalidad del lenguaje le permite describir de manera concisa las transformaciones sobre los datos. En mi opinión, Python carece de algunas herramientas que ayudarían a describir las transformaciones de datos de manera más conveniente y complementar el componente funcional del lenguaje, en particular, las "canalizaciones de funciones" y su aplicación parcial. Por eso, en este post echo agua sobre la posibilidad y necesidad de estos fondos con experimentos para su implementación. Vine de muchas maneras para recibir críticas. ¡Disfruta leyendo!
Brevemente sobre FP en Python y por qué no hay suficientes canalizaciones, por ejemplo
Python tiene algunas herramientas básicas bastante útiles como map (), reduce (), filter (), funciones lambda, iteradores y generadores. Aconsejo a todos los que no estén familiarizados con este artículo . En general, todo le permite describir rápida y naturalmente transformaciones en listas, tuplas, etc. Muy a menudo (conmigo y mis amigos pitonistas) lo que sucedeun trazador de líneas- esencialmente un conjunto de transformaciones secuenciales, filtros, por ejemplo:
Kata con CodeWars : Find
La tarea es bastante simple, desafortunadamente (pero afortunadamente para esta publicación), no hay mejores soluciones que las de frente.
Mi decisión:
def sum_dig_pow(a, b): # range(a, b + 1) will be studied by the function
powered_sum = lambda x: sum([v**(i+1) for i,v in enumerate(map(lambda x: int(x), list(str(x))))])
return [i for i in range(a,b+1) if powered_sum(i)==i]
Usando los medios de FP tal como están, obtenemos un infierno entre paréntesis "de adentro hacia afuera". El oleoducto podría arreglar eso.
Canalizaciones de funciones
Por sim me refiero en el caso ideal (el operador "|" es preferencia personal):
# f3(f2(f1(x)))
f1 | f2 | f3 >> x
pipeline = f1 | f2 | f3
pipeline(x)
pipeline2 = f4 | f5
pipeline3 = pipeline | pipeline2 | f6
...
powered_sum ( ):
powered_sum = str | list | map(lambda x: int(x), *args) | enumerate | [v**(i+1) for i,v in *args] | sum
, . args . , ( ):
from copy import deepcopy
class CreatePipeline:
def __init__(self, data=None):
self.stack = []
if data is not None:
self.args = data
def __or__(self, f):
new = deepcopy(self)
new.stack.append(f)
return new
def __rshift__(self, v):
new = deepcopy(self)
new.args = v
return new
def call_logic(self, *args):
for f in self.stack:
if type(args) is tuple:
args = f(*args)
else:
args = f(args)
return args
def __call__(self, *args):
if 'args' in self.__dict__:
return self.call_logic(self.args)
else:
return self.call_logic(*args)
, , , kwargs, .
pipe = CreatePipeline()
powered_sum = pipe | str | list | (lambda l: map(lambda x: int(x), l)) | enumerate | (lambda e: [v**(i+1) for i,v in e]) | sum
, , , , , .
( ):
def f_partitial (x,y,z):
return x+y+z
v = f_partial(1,2)
# type(v) = - f_partial, : ['z']
print(v(3))
#
print(f_partial(1,2,3))
( ). pipe :
powered_sum = pipe | str | list | map(lambda x: int(x)) | enumerate | (lambda e: [v**(i+1) for i,v in e]) | sum
# map
# map(lambda x: int(x))()
map(lambda x: int(x)) .
:
from inspect import getfullargspec
from copy import deepcopy
class CreatePartFunction:
def __init__(self, f):
self.f = f
self.values = []
def __call__(self, *args):
args_f = getfullargspec(self.f)[0]
if len(args) + len(self.values) < len(args_f):
new = deepcopy(self)
new.values = new.values + list(args)
return new
elif len(self.values) + len(args) == len(args_f):
return self.f(*tuple(self.values + list(args)))
:
# inspect map
m = lambda f, l: map(f, l)
#
pmap = CreatePartFunction(m)
powered_sum = pipe | str | list | pmap(lambda x: int(x)) | enumerate | (lambda e: [v**(i+1) for i,v in e]) | sum
( ), , , , :
def f (x,y,z):
return x+y+z
f = CreatePartFunction(f)
#
print(f(1,2,3))
#
print(f(1,2)(3))
print(f(1)(2,3))
#
# 2(3) - int callable
print(f(1)(2)(3))
#
print((f(1)(2))(3))
, , , , , , , .