2010-04-16 4 views
6

ich einige Seiten aus WikiVS geht zu Ende war, dass ich zitiere aus:Restrictons von Python im Vergleich zu Rubin: LAMBDA

weil lambdas in Python sind Ausdrücke beschränkt und kann nicht Aussagen enthalten

Ich würde gerne wissen, was wäre ein gutes Beispiel (oder mehr), wo diese Einschränkung wäre, vorzugsweise im Vergleich zu der Sprache Ruby.

Vielen Dank für Ihre Antworten, Kommentare und Feedback!

+2

Lambdas sind Ausdrücke * per Definition *. –

Antwort

12

Ich glaube nicht, dass Sie wirklich nach Lambdas fragen, aber Inline-Funktionen.

Dies ist wirklich eine von Pythons ernsthaft lästigen Einschränkungen: Sie können eine Funktion (eine echte Funktion, nicht nur einen Ausdruck) inline definieren; du musst ihm einen Namen geben. Dies ist sehr frustrierend, da jede andere moderne Skriptsprache dies tut und es oft sehr schmerzhaft ist, Funktionen aus der Reihe zu bringen. Es ist auch frustrierend, weil ich das Gefühl habe, dass Python-Bytecode das trivial darstellen kann - es ist nur die Sprachsyntax, die das nicht kann.

Javascript:

responses = { 
     "resp1": { 
       "start": function() { ... }, 
       "stop": function() { ... }, 
     }, 
     "resp2": { 
       "start": function() { ... }, 
       "stop": function() { ... }, 
     }, 
     ... 
} 
responses["resp1"]["start"](); 

Lua:

responses = { 
     resp1 = { 
       start = function() ... end; 
       end = function() ... end; 
     }; 
     ... 
} 
responses.resp1.start(); 

Rubin:

responses = { 
    "resp1" => { 
     "start" => lambda { }, 
     "stop" => lambda { }, 
    }, 
} 
responses["resp1"]["start"].call 

Python:

def resp1_start(): 
    pass 
def resp1_stop(): 
    pass 
responses = { 
    "resp1": { 
     "start": resp1_start, 
     "stop": resp1_stop, 
    }, 
} 
responses["resp1"]["start"]() 

Beachten Sie, dass JavaScript und Lua keine lambdas haben: Sie haben keinen Grund zu existieren, da Inline-Funktionen sie viel natürlicher und allgemeiner abdecken.

Ich würde das wahrscheinlich als die nervigste tägliche Python-Einschränkung bezeichnen.

+1

..dies ist ein hässlicher Hack .. << haben Sie Links, die darauf hinweisen? – Shyam

+2

Ich gab ein Beispiel für Rubys zweiten Klasse "Inline-Funktion" -Mechanismus. –

+6

@Glenn, Ruby hat keine Funktionen, es hat nur Methoden. Rubys anonyme Funktionen (Lambda-Funktionen) sind eigentlich Funktoren. Und es gibt nichts Hässliches oder Hack-ähnliches an ihnen. Es ist einfach eine Konsequenz der Nachrichtenübergabe OO. Scala macht dasselbe, ebenso Smalltalk. – horseyguy

9

Die am häufigsten vorkommende Situation in Bezug auf Anweisungen ist wahrscheinlich Python 2.X print Anweisung.

Zum Beispiel

say_hi = lambda name: "Hello " + name 

funktioniert wie erwartet.

Aber das wird nicht kompilieren:

say_hi = lambda name: print "Hello " + name 

weil print in Python keine richtige Funktion ist 2.

>>> say_hi = lambda name: "Hello " + name 
>>> say_hi("Mark") 
'Hello Mark' 
>>> 
>>> say_hi = lambda name: print "Hello " + name 
SyntaxError: invalid syntax 

Der Rest der Aussagen neben print kann in the Python documentation online finden:

simple_stmt ::= expression_stmt 
       | assert_stmt 
       | assignment_stmt 
       | augmented_assignment_stmt 
       | pass_stmt 
       | del_stmt 
       | print_stmt 
       | return_stmt 
       | yield_stmt 
       | raise_stmt 
       | break_stmt 
       | continue_stmt 
       | import_stmt 
       | global_stmt 
       | exec_stmt 

können Sie versuchen, den Rest von ihnen in der REPL aus, wenn man sie nicht sehen wollen:

>> assert(True) 
>>> assert_lambda = lambda: assert(True) 
SyntaxError: invalid syntax 
>>> pass 
>>> pass_lambda = lambda: pass 
SyntaxError: invalid syntax 

Ich bin nicht sicher, was zwischen Python Parallelen gibt es lambda Einschränkungen und Rubys proc oder lambda. In Ruby ist alles eine Nachricht, also haben Sie keine Schlüsselwörter (okay, Sie haben Schlüsselwörter, aber Sie haben keine Schlüsselwörter, die scheinen, Funktionen wie Pythons print zu sein). Aus der Spitze meines Kopfes gibt es keine leicht zu verwechselnden Ruby-Konstrukte, die in einem proc fehlschlagen werden.

+1

Vielen Dank für Ihre Zeit, dieses zu schreiben! – Shyam

4

Ein Beispiel, das manchmal mit mir kommen hat, ist so etwas wie diese:

def convert(value): 
    n = expensive_op(value) 
    return (n, n + 1) 

new_list = map(convert, old_list) 

Obwohl es kurz und süß genug ist, können Sie es zu einem Lambda nicht konvertieren, ohne expensive_op() zweimal laufen zu (die , wie der Name schon sagt, Sie wollen nicht), dh Sie

new_list = map(lambda v: (expensive_op(v), expensive_op(v) + 1), old_list) 

weil Zuordnung (n = ...) ist eine Aussage zu tun haben würde.

+0

'new_list = map (lambda v: Tupel (x.next() + y für x, y in zip (* (itertools.tee ([teur_op (v)]), (0, 1)))), old_list) 'Nicht dass du jemals irgendwas schreiben würdest, natürlich ... –

+0

@Ignacio: Nun, ich * habe darüber nachgedacht, eine solche Alternative zu der Antwort hinzuzufügen. Aber selbst wenn ich darüber nachdachte, tat es weh ;-) – balpha

+0

'new_list = [(r, r + 1) für r in (teures_op (v) für v in old_list)]' - das wird einmal ausgeführt und der interne Ausdruck ist faul, also es ruft aus und erstellt ein Tupel nach Bedarf - nur die externe Liste wird tatsächlich erstellt. – viraptor

1

lambda ist einfach eine Verknüpfung in Python, um eine Funktion zu definieren, die einen einfachen Ausdruck zurückgibt. Dies ist keine Einschränkung in irgendeiner sinnvollen Weise. Wenn Sie mehr als einen Ausdruck benötigen, verwenden Sie einfach eine Funktion: Es gibt nichts Sie können mit einem Lambda tun, die Sie nicht mit einer Funktion tun können.

Die einzigen Nachteile der Verwendung einer Funktion anstelle eines Lambda sind, dass die Funktion auf 1 oder mehrere separate Zeilen definiert werden muss (so können Sie einige Stelle im Vergleich zum Lambda verlieren), und Sie müssen einen Namen für erfinden die Funktion (aber wenn Sie nicht an eine denken, dann funktioniert f im Allgemeinen).

Alle anderen Gründe, die Leute denken, dass sie ein Lambda verwenden müssen (wie das Zugreifen auf verschachtelte Variablen oder das Erzeugen von vielen Lambdas mit separaten Standardargumenten), funktionieren genauso gut mit einer Funktion.

Der große Vorteil der Verwendung einer benannten Funktion ist natürlich, dass wenn Sie einen Fehler machen, Sie eine sinnvolle Stapelverfolgung erhalten. Ich habe mich gestern beißen lassen, als ich eine Stack-Spur mit einem Lambda und keinem Zusammenhang darüber bekam, welches Lambda es war.

+0

Sie sollten Kontext in Backtraces für Lambdas erhalten, genau wie Funktionen. –

+0

Sie tun, aber in diesem Fall beschwerte sich der Stack-Trace, dass es den Lambda nicht beizen konnte, so dass das Lambda nicht wirklich Teil des Call-Stacks war. Wenn es eine lokale Funktion gewesen wäre, hätte ich zumindest einen Namen gehabt. Sie erhalten ein ähnliches Problem, wenn Sie die falschen Argumente haben, wenn Sie versuchen, etwas aufzurufen: Das Backtrace enthält keinen Kontext für die Callable, die den TypeError generiert hat. – Duncan

2

Anstelle von f=lambda s:pass können Sie f=lambda s:None tun.