10

Ich arbeite in Python. Vor kurzem entdeckte ich ein wundervolles kleines Paket namens fn. Ich habe es für die Funktionszusammensetzung verwendet.Bessere Funktionszusammensetzung in Python

Zum Beispiel statt:

baz(bar(foo(x)))) 

mit fn, können Sie schreiben:

(F() >> foo >> bar >> baz)(x) . 

Als ich das sah, habe ich sofort von Clojure dachte:

(-> x foo bar baz) . 

Aber Beachten Sie, wie in Clojure die Eingabe auf der linken Seite ist. Ich frage mich, ob das in Python/Fn möglich ist.

+2

Während der Bediener Verhalten Überlastung interessant, mir dies scheint wie eine schlechte Sache in echten Code zu tun. –

+0

Es gibt keine Möglichkeit, die genaue Syntax in Python zu verwenden, wenn Sie das fragen. Sie können es auf verschiedene Arten annähern. Was genau ist dir syntaktisch wichtig? – BrenBarn

+0

Den Fluss von links nach rechts halten.Gegenwärtig ist das Argument für die komponierte Funktion am Ende. Es wäre klarer, wenn ich F() >> x >> foo >> bar >> baz oder ähnliches schreiben könnte. –

Antwort

9

Sie können nicht die genaue Syntax replizieren, aber Sie können etwas ähnliches machen:

def f(*args): 
    result = args[0] 

    for func in args[1:]: 
     result = func(result) 

    return result 

scheint zu funktionieren:

>>> f('a test', reversed, sorted, ''.join) 
' aestt' 
2

Sie können nicht, dass die genaue Syntax erhalten, obwohl Sie Holen Sie sich etwas wie F(x)(foo, bar, baz). Hier ist ein einfaches Beispiel:

class F(object): 
    def __init__(self, arg): 
     self.arg = arg 

    def __call__(self, *funcs): 
     arg = self.arg 
     for f in funcs: 
      arg = f(arg) 
     return arg 

def a(x): 
    return x+2 
def b(x): 
    return x**2 
def c(x): 
    return 3*x 

>>> F(2)(a, b, c) 
48 
>>> F(2)(c, b, a) 
38 

Dies ist ein bisschen anders als Blender Antwort, da sie das Argument speichern, die später wiederverwendet werden können mit unterschiedlichen Funktionen.

Dies ist eine Art wie das Gegenteil von normalen Funktion Anwendung: anstatt die Funktion im Vordergrund und einige Argumente später angeben, geben Sie das Argument und lassen Sie die Funktion (en) später angegeben werden. Es ist ein interessantes Spielzeug, aber es ist schwer zu denken, warum du das wirklich willst.

1

Wenn Sie fn verwenden, mit einem kleinen Hack Sie ein bisschen näher an Clojure Syntax bekommen:

>>> def r(x): return lambda: x 
>>> (F() >> r(x) >> foo >> bar >> baz)() 

Sehen Sie, wie ich eine andere Funktion zu Beginn der Zusammensetzung Kette hinzugefügt, die x gerade zurück wenn angerufen. Das Problem dabei ist, dass Sie Ihre kompilierte Funktion nur noch ohne Argumente aufrufen müssen.

Ich denke @ Blenders Antwort ist Ihre beste Wette, die Clojure Thread-Funktion in Python zu emulieren.

0

kam ich mit diesem

def _composition(arg, *funcs_and_args): 
    """ 
    _composition(
     [1,2,3], 
     (filter, lambda x: x % 2 == 1), 
     (map, lambda x: x+3) 
    ) 
    #=> [4, 6] 
    """ 
    for func_and_args in funcs_and_args: 
     func, *b = func_and_args 
     arg = func(*b, arg) 
    return(arg) 
0

up Dies scheint für einfache Eingabe zu arbeiten. Nicht sicher, dass es den Aufwand für komplexe Eingabe wert ist, z. B. ((42, 'spam'), {'spam': 42}).

def compose(function, *functions): 
    return function if not functions else \ 
      lambda *args, **kwargs: function(compose(*functions)(*args, **kwargs)) 

def rcompose(*functions): 
    return compose(*reversed(functions)) 

def postfix(arg, *functions): 
    return rcompose(*functions)(arg) 

Beispiel:

>>> postfix(1, str, len, hex) 
'0x1' 
>>> postfix(1, hex, len) 
3 
Verwandte Themen