Je n'ai pas beaucoup d'expérience avec Python. J'essaie de coder dans un style fonctionnel comme je suis habitué à partir de Java et JavaScript, par exemple
tmp = ((hero, get_movies(hero)) for hero in get_heroes('jedi')) result = ((hero, movies) for (hero, movies) in tmp if movies.contains('A New Hope')
J'essaie de faire quelque chose de similaire en Python mais je ne peux pas obtenir la même chose style de chaînage. J'ai dû le décomposer en deux déclarations, ce que je n'aime pas:
var result = getHeroes('Jedi') .map(hero => { hero: hero, movies: getMovies(hero) }) .filter(x => x.movies.contains('A New Hope'));
J'ai deux questions:
Merci.
4 Réponses :
IMO, ils font cela dans un style fonctionnel en python (pas pythonique en fait), en utilisant map
et filter
:
result = ((hero, get_movies(hero)) for hero in get_heroes("jedi") if "A new hope" in get_movies(hero))
La manière pythonique (pas très fonctionnelle) serait d'utiliser une expression de générateur:
result = filter ( lambda x: x[1].contains('A New Hope'), map( lambda x: (hero, get_movies(hero)), get_heroes('jedi') ) )
les générateurs et les expressions génératrices (y compris les compréhensions de listes, etc.) SONT en fait typiques de la programmation fonctionnelle - FWIW, les compréhensions de listes viennent de Haskell.
En tant que personne qui adore la programmation fonctionnelle, n'écrivez pas dans un style fonctionnel en Python .
Cette règle dure et rapide est un peu maladroite, et il existe certainement des moyens de faire quoi vous essayez de faire en utilisant des outils fonctionnels typiques tels que map
, filter
et reduction
(appelé functools.reduce
en Python), mais il est probable que votre code fonctionnel aura l'air plus laid que sin, auquel cas il n'y a aucune raison de le préférer à quelque chose d'impératif et de joli.
result = [(hero, movies) for hero in get_heros("Jedi") for movies in [get_movies(hero)] if "A New Hope" in movies]
Cela pourrait être fait avec une compréhension de liste, mais est probablement moins lisible.
result = [] for hero in get_heros("Jedi"): movies = get_movies(hero) for movie in movies: if "A New Hope" in movies: result.append((hero, movies))
Votre exemple de boucle for
imbriquée est tout sauf Pythonic. Quel est le problème avec les expressions et les compréhensions générées?
@EliKorvigo rien quand ces expressions peuvent être concises, mais le genre de compréhension imbriquée nécessaire à cette logique est encombrant. En fait, ma logique est fausse - il veut (héros, films) si "Un nouvel espoir" dans les films
.
Je suis d'accord avec @AdamSmith ici: une compréhension de liste imbriquée ne gagne rien en lisibilité sur les boucles imbriquées explicites
@AdamSmith Je pense que la deuxième façon est ce que je voulais, merci
@AdamSmith J'aurais personnellement utilisé une liste de compilation dans la boucle for, c'est-à-dire pour l'héroïne get heroes ("Jedi"): results.extend ([film pour film dans get_movies (héros) si "Un nouvel espoir" dans les films ])
@brunodesthuilliers sûr: mélanger et assortir selon le cas :)
@AdamSmith Je suis totalement d'accord avec vous, mais rxpy rend les choses difficiles.
Si vous êtes prêt à utiliser des bibliothèques tierces, je suggère fn.py
avec son sucre syntaxique pour les compositions
program = ( F(map, lambda hero: dict(hero=hero, movies=getMovies(hero))) >> (filter, lambda x: 'A New Hope' in x['movies']) >> list ) result = program(getHeroes('Jedi')) # or even result = (F(getHeroes) >> program)('Jedi')
Vous pouvez supprimer le dernier élément dans la composition, si vous ne voulez pas de liste, bien que les itérateurs / générateurs avec état ne soient pas très fonctionnels. Les objets F
encapsulent les éléments appelables et facilitent l'application partielle et la composition. Une chaîne d'expressions F
est une nouvelle fonction qui peut être utilisée plusieurs fois. C'est plus proche de la programmation fonctionnelle au sens classique: les programmes sont des compositions:
from fn import F result = ( F(map, lambda hero: dict(hero=hero, movies=getMovies(hero))) >> (filter, lambda x: 'A New Hope' in x['movies']) >> list )(getHeroes('Jedi'))
C'est une approche sincère de ce qui pourrait être réellement pythonique et fonctionnel. Je pense que ce serait «mieux» si vous nommez la fonction que vous créez et l'appliquez ensuite séparément aux données.
Pourquoi Python n'est-il pas très bon pour la programmation fonctionnelle?
Ce javascript ne semble pas très fonctionnel en fait.
Eh bien, vous pouvez faire fonctionnel, mais il y a de fortes chances que vos collaborateurs vous détestent surtout pour cela (: si vous travaillez également avec une personne fonctionnelle, allez-y par tous les moyens (:
@JoeyMallone ne sont pas non plus JavaScript / Java, mais l'OP veut écrire de cette façon