6 votes

Restrictions de Python par rapport à Ruby : lambda's

Je passais en revue quelques pages de WikiVS, dont je cite :

parce que les lambdas en Python sont limitées aux expressions et ne peuvent pas contenir des instructions

J'aimerais savoir quel serait un bon exemple (ou plusieurs) où cette restriction serait, de préférence par rapport au langage Ruby.

Merci pour vos réponses, commentaires et retours !

14voto

Glenn Maynard Points 24451

Je ne pense pas que vous parlez vraiment de lambdas, mais de fonctions inline.

C'est vraiment l'une des limitations sérieusement ennuyeuses de Python : vous ne pouvez pas définir une fonction (une vraie fonction, pas juste une expression) inline ; vous devez lui donner un nom. C'est très frustrant, car chaque autre langage de script moderne le fait et il est souvent très pénible de déplacer des fonctions hors ligne. C'est aussi frustrant car j'ai l'impression que le bytecode Python pourrait le représenter de manière triviale - c'est juste la syntaxe du langage qui ne peut pas.

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();

Ruby :

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"]()

Remarquez que JavaScript et Lua n'ont pas de lambdas : ils n'ont aucune raison d'exister, car les fonctions inline les couvrent de manière beaucoup plus naturelle et générale.

Je classerais probablement cela comme la limitation la plus ennuyeuse de Python dans la vie de tous les jours.

9voto

Mark Rushakoff Points 97350

La situation la plus courante concernant les déclarations est probablement celle du print en Python 2.X.

Par exemple,

say_hi = lambda name: "Hello " + name

fonctionne comme prévu.

Mais cela ne compilera pas :

say_hi = lambda name: print "Hello " + name

car print n'est pas une fonction appropriée en Python 2.

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

Le reste des déclarations en dehors de print peuvent être trouvées dans la documentation Python en ligne:

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

Vous pouvez essayer le reste de ces déclarations dans le REPL si vous voulez les voir échouer :

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

Je ne suis pas sûr des parallèles entre les restrictions du lambda de Python et le proc ou le lambda de Ruby. En Ruby, tout est un message, donc vous n'avez pas de mots-clés (d'accord, vous avez des mots-clés, mais vous n'avez pas de mots-clés qui semblent être des fonctions comme le print de Python). De mémoire, il n'y a pas de constructions Ruby facilement confondues qui échoueraient dans un proc.

4voto

balpha Points 18387

Un exemple qui m'est parfois apparu est un peu comme celui-ci :

def convertir(valeur):
    n = operation_couteuse(valeur)
    return (n, n + 1)

nouvelle_liste = map(convertir, ancienne_liste)

Bien que ce soit assez court et simple, vous ne pouvez pas le convertir en lambda sans devoir exécuter operation_couteuse() deux fois (ce que, comme son nom l'indique, vous ne voulez pas faire), c'est-à-dire que vous devriez faire

nouvelle_liste = map(lambda v: (operation_couteuse(v), operation_couteuse(v) + 1), ancienne_liste)

parce que l'assignation (n = ...) est une instruction.

2voto

bdforbes Points 643

Au lieu de f=lambda s:pass vous pouvez faire f=lambda s:None.

1voto

Duncan Points 25356

lambda est simplement un raccourci en Python pour définir une fonction qui retourne une expression simple. Cela n'est en aucun cas une restriction significative. Si vous avez besoin de plus qu'une seule expression, utilisez simplement une fonction : il n'y a rien que vous pouvez faire avec une lambda que vous ne pouvez pas faire avec une fonction.

Les seuls inconvénients à utiliser une fonction à la place d'une lambda sont que la fonction doit être définie sur une ou plusieurs lignes séparées (vous risquez donc de perdre un peu de localité par rapport à la lambda) et vous devez inventer un nom pour la fonction (mais si vous n'en trouvez pas, f fonctionne généralement).

Toutes les autres raisons pour lesquelles les gens pensent qu'ils doivent utiliser une lambda (comme l'accès à des variables imbriquées ou la génération de nombreuses lambdas avec des arguments par défaut séparés) fonctionneront tout aussi bien avec une fonction.

Le grand avantage d'utiliser une fonction nommée est bien sûr que lorsque quelque chose ne va pas, vous obtenez une trace de la pile significative. Cela m'est arrivé hier lorsque j'ai eu une trace de pile impliquant une lambda sans contexte sur laquelle elle était.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X