J’ai récemment regardé une conférence de Dave Cheeney sur les fonctions de première classe en Go. Sachant que Python est également capable de les prendre en charge, sont-elles utilisables de la même manière? Absolument.

J’utilise Python depuis un moment maintenant. C’est un bon complément à Bash lorsqu’il est question d’intégrer une logique assez complexe dans des scripts. Le code en ressort plus propre et lisible lors de la manipulation de données simples.

Lorsqu’on apprend à utiliser un langage, il est important de garder à l’esprit ce qui ne peut uniquement être fait en utilisant ses fonctionnalités innées. Par exemple, apprendre à utiliser – et non pas abuser – les listes, pour cela une chose importante est de comprendre à quelles problématiques elles répondent. C’est une des règles crucial pour maîtriser Python, et plus globalement la programmation objet. Cet article explore ce qui peut être fait avec des fonctions de première classe en Python tout en conservant un code propre.

Tout d’abord, que signifie “Python supporte les fonctions de première classe”? En termes simples, cela veut dire que les fonctions peuvent être utilisées comme s’il s’agissait de valeurs. Vous pouvez les stocker dans des variables, les passer à d’autres fonctions en tant qu’arguments, etc.

Dave Cheney a utilisé une calculatrice simple à titre d’exemple, commençons par reproduire celui-ci. En voici une implémentation possible :

Quelques connaissances en Python – plus généralement de n’importe quel langage orienté objet – suffisent à comprendre le code ci-dessus. Il peut être utilisé comme suit:

Maintenant que la calculatrice fonctionne, ce code est importable dans n’importe quel script qui pourrait en avoir besoin. Mais qu’en est-il de la division sachant que la celle-ci n’est pas encore implémentée? Quid du calcul d’un logarithme? de factorielles? Ces opérations pourraient facilement être ajoutées en écrivant de nouvelles méthodes dans la classe Calculator. Idéalement, cette calculatrice devrait être capable de résoudre n’importe quel type de calcul sans avoir à modifier son code.

C’est ici que les fonctions de première classe entrent en jeu. Souvenez-vous de la définition précédente: les fonctions peuvent être stockées dans des variables et passées sous forme d’arguments à d’autres fonctions. Voici un code pour montrer comment les fonctions peuvent être stockées dans des variables:

Dans le code ci-dessus, rand est une variable de type “fonction”. Notez que also_rand a exactement la même valeur que rand.

Une fonction peut également être passée en tant qu’argument à d’autres fonctions, comme ceci:

Cela rappellera à de nombreux développeurs Python des fonctions telles que map et filter, prenant pour arguments des fonctions, tout comme call_three_times ci-dessus. C’est ce qu’on appelle la programmation fonctionnelle.

Retour à la calculatrice. Les utilisateurs devraient pouvoir passer n’importe quelle fonction à la calculatrice et la laisser l’exécuter. Voici comment cela pourrait être codé:

Le code en ressort plus court, ce qui est normal : la calculatrice peut tout faire sans rien implémenter en plus. Voici quelques exemples d’opérations:

Tout cela fonctionne, mais le code n’est pas très flexible. Il faut une fonction entière pour ajouter 2 et une autre si on veut ajouter 5. Ce sera vite ingérable.

De ce fait, on a içi un bon cas d’usage des fonctions lambdas. Elles permettent de définir des fonctions anonymes courtes, c’est-à-dire des fonctions qui ne sont pas explicitement définies avec def. En les utilisant, le code ci-dessus devient:

Bien que ne pas avoir à définir des fonctions pour chaque opération soit une bonne chose, il y a trop de lambda. Le code ci-dessus n’est pas facile à lire. Il doit être rendu plus lisible.

Pourquoi ne pas remplacer ces lambdas par des fonctions aux noms explicites? Inspirons nous de add_two défini plus haut mais avec plus de ré-utilisabilité.

La lisibilité du code calc.do(add(2)) est difficilement rivalisable. Ci-dessus, add et multiply sont des fonctions retournant une fonction, ensuite appelée par la calculatrice. La programmation fonctionnelle permet un code très lisible.

Rappelons que les lambdas ne peuvent définir qu’une seule expression, ce qui les rend idéales pour des choses simples comme une addition, mais insuffisantes pour une logique plus complexe. Les lambdas ne sont pas les seules fonctions à notre disposition. Toute fonction peut être retournée.

La calculatrice peut maintenant appliquer n’importe quel comportement décrit par une fonction. La seule condition préalable est que la fonction transmise à la méthode do de la calculatrice prenne une valeur en argument et renvoie une valeur. Ainsi, toute fonction correspondant à ces critères peut être utilisée, y compris les fonctions d’autres bibliothèques.

Par exemple:

La prise en charge des fonctions de première classe n’est pas une fonctionnalité superficielle. Bien que l’utilisation de fonctions de cette manière puisse sembler intimidante au début, on s’y habitue assez rapidement.

Un élément à retenir de cet article est que les fonctions peuvent être utilisées pour créer d’autres fonctions. Bien que cela puisse paraître compliqué, le code en ressortira plus lisible et donc plus compréhensible. Dès lors, une logique complexe pourra être écrite et configurable, le tout grâce à des règles simples.

La communauté Go utilise abondamment les fonctions de première classe. Notre exemple illustre le fait que cette physionomie est également implémentable en Python.