Head et tail de liste en Python 3
Bien que Python ne soit pas un langage de programmation fonctionnelle, il incorpore un certain nombre de fonctionnalités typiques de ces langages. Ainsi les fonctions anonymes lambda
, la compréhension de liste, ou encore les fonctions built-in map()
, filter()
et reduce()
(cette dernière ayant été supprimée dans Python 3).
La programmation fonctionnelle est caractérisée par une utilisation intensive des listes, et en particulier par de nombreuses opérations récursives sur ces dernières. On est donc souvent amené à vouloir récupérer le premier élément d’une liste, sa tête ou head, et l’ensemble des éléments restants, sa queue ou tail. Ce qui s’écrit donc trivialement avec la fonction f()
retournant une liste :
head, tail = f()[0], f()[1:]
Le premier problème ici est le double appel de la fonction f()
, que l'on peut facilement corriger grâce à l'utilisation d'une variable intermédiaire result
:
result = f()
head, tail = result[0], result[1:]
Le second problème est la lourdeur syntaxique de l’ensemble, avec la variable intermédiaire et le double usage du []
(le __getitem__
des listes en Python). On aimerait bien à la place avoir une syntaxe plus adaptée, c'est-à-dire plus proche de celles utilisées par les langages de programmation fonctionnelle, comme par exemple Erlang :
[Head|Tail] = Result
Et comme toujours avec Python, le langage se bonifie grâce à une PEP (Python Enhancement Proposal), en l’occurence la PEP 3132 intitulée Extended Iterable Unpacking. Ainsi, depuis Python 3.0, on peut utiliser une nouvelle syntaxe qui reprend celle des star-args (*args) des fonctions Python :
head, *tail = result
Ceci se teste facilement dans un shell Python 3 :
>>> result = [1, 2, 3, 4]
>>> head, *tail = result
>>> head
>>> 1
>>> tail
>>> [2, 3, 4]
On a donc maintenant une syntaxe tout à fait satisfaisante, très lisible et facilitant un style de programmation fonctionnel. Ce qui est encore plus intéressant avec cette notation, c’est qu’elle ne se limite pas au couple head
et tail
, et peut ainsi être déclinée de bien des manières tout à fait intéressantes comme par exemple :
>>> result = [1, 2, 3, 4]
>>> head, *body, tail = result
>>> head
>>> 1
>>> body
>>> [2, 3]
>>> tail
>>> 4
Python 3 est sorti depuis plus de deux ans et, sans être révolutionnaire, il apporte de nombreuses améliorations à Python 2 qui valent le coup d’être découvertes et utilisées !