2011-02-10 12 views
12

Clojure tiene una macro "->" que inserta cada expresión recursivamente como primer argumento de la siguiente expresión.Función de estilo Clojure "subprocesamiento" en Python

Esto significa que podría escribir:

(-> arg f1 f2 f3) 

y se comporta como (tuberías shell):

f3(f2(f1(arg))) 

me gustaría hacer esto en Python; ¡Sin embargo, la búsqueda parece ser una pesadilla! No pude buscar "->", y tampoco pude buscar la función de Python enhebrado!

¿Hay alguna manera de sobrecargar, por ejemplo, el | operador para que pueda escribir esto en Python?

arg | f1 | f2 | f3 

¡Gracias!

+0

dependig en lo loco que desea llegar, puede ser vale la pena mirar pitón 'hy' en https://github.com/hylang/hy. – joefromct

Respuesta

12

Puede implementar fácilmente algo como esto usted mismo.

def compose(current_value, *args): 
    for func in args: 
     current_value = func(current_value) 
    return current_value 

def double(n): 
    return 2*n 

print compose(5, double, double) # prints 20 
-1

No, no hay (al menos cordialmente). Tampoco te gustaría. ¿Por qué no simplemente escribir f3(f2(f1(arg)))? O mejor aún, modele su problema de una manera que no requiera recurrencia.

Es posible que pueda sobrecargar | envolviendo expresiones en una clase y definiendo __or__ en esa clase, pero por favor, por el amor de Guido, no haga eso.

También podría hacer lo que btilly escribió, pero tampoco lo recomendaría. Trabaja dentro de lo que el lenguaje te brinda.

+1

¿eh, por qué mencionas la recursividad de la nada? –

+0

@Jochen '->' en Clojure es recursivo en la naturaleza –

+0

Sé que a Guido no le gustan las técnicas funcionales, pero esa no es una razón para no decirle a las personas que les gusta cómo usarlas en Python. – btilly

16

O, posiblemente, utilizar la función de reducir la siguiente manera:

reduce(lambda x,f : f(x), [f1,f2,f3], arg) 
+0

Esta es una forma muy limpia y funcional de implementarlo. ¡Gracias! Las otras formas que se presentan hacen lo mismo, pero "arg" está al frente y creo que eso hace una gran diferencia en términos del flujo de escritura del código. – Vimal

+1

@Vimal: si le preocupa ordenar, puede usar reducir (lambda x, f: f (x), [arg, f1, f2, f3]). – Howard

3

Aunque simpatizo con el deseo de crear nuevas construcciones fresco del lenguaje (a la Lisp macros), que no es realmente el pitón filosofía para hacer esto:

>>> import this 
[...] 
There should be one-- and preferably only one --obvious way to do it. 

Pero como han dicho los encuestados, puede hacer su función de encadenamiento en una variedad de formas. Aquí está uno que es tal vez más explícitamente Lisp, si que se adapte a su fantasía:

a = lambda x: x*2 
b = lambda x: x+1 

def chain(first, *args): 
    if len(args) == 0: 
     return first 
    else: 
     return first(chain(*args)) 

print chain(b, a, 1) 
+0

Necesitamos sacar el Lisp de Python, no ponerlo más ... –

+4

Las influencias de ceceo de Python son lo que lo hace genial. – Phob

+0

Lo apropiado de Lisp en Python depende del proyecto en cuestión. La demografía de la comunidad potencial de desarrolladores tiene un gran peso aquí. ¿Escribiendo una biblioteca de análisis? Lispiness para la victoria! ¿Haciendo números? Use Lisp y pierda el 90% de su grupo de desarrolladores. – MRocklin

8

Sobre la base de la solución de Howard:

def T(*args): 
    return reduce(lambda l, r: r(l), args) 

def dbl(n): 
    return 2*n 

T(5,dbl,dbl) 
#=> 20 

T(5,dbl,dbl,lambda x: 3*x) 
#=> 60 
1

Hay una thread function en la biblioteca pytoolz (en realidad hay dos; hacen cosas ligeramente diferentes en las funciones de múltiples ar guments).

También hay una implementación cython de la biblioteca pytoolz llamada cytoolz que es probablemente más eficiente. Se puede instalar usando pip.

0

Un poco tarde para la fiesta, pero aquí hay un método más limpio, imo.Se adaptará a la mayoría de las necesidades de FP.

def stream(*args): 
    return reduce(lambda a, t: t[0](t[1], a), args[1:], args[0]) 

un mapa básico, filtro, reducir:

>>> my_list = [1, 2, 3, 4, 5] 
>>> stream(my_list, 
... (map, lambda x: x ** 2), 
... (filter, lambda x: x < 20), 
... (reduce, lambda a, x: a + x)) 
30