Les opérateurs étoile (* et **) en Python

En Python, chacun sait que l’opérateur * permet d’effectuer une multiplication sur des opérandes numériques, ou à répéter un opérande quelconque, tandis que l’opérateur ** permet d’effectuer une élévation à une puissance quelconque d’un opérande numérique :
print (2*3)
print (2*'Hello, world!')
print (2**3)
6
Hello, world!Hello, world!
8
Ce qui est moins connu, car elle est assez mal documentée, c’est la possibilité d’utiliser ces opérateurs pour du déballage (unpacking) d’itérables divers en vue de constituer un autre itérable. Par exemple :
x = ['A', 'B']
y = ('C', 'D')
z = [*x, *y]
print (z)
['A', 'B', 'C', 'D']
Comment est-il possible d’utiliser ces opérateurs de cette manière ? Et pour quoi faire ? L’exploration de la documentation de Python permet de constater qu’ils peuvent servir dans deux circonstances : pour créer des itérables, et pour fournir des arguments à une fonction. Explications…
Mise à jour du 19/05/2018 : Mention de notations supplémentaires pour créer un itérable à partir d’un autre.
Continuer la lecture de « Les opérateurs étoile (* et **) en Python »
Les opérateurs étoile (* et **) en Python

Syntaxes avancées (car ramassées) en Python

Il y a mille manières d’exprimer ce qu’on désire en langage naturel, et il en va de même avec un langage de programmation.
Certaines fomulations peuvent être clairement plus laconiques que d’autres, et d’aucuns considèrent que c’est démontrer sa maîtrise du langage que de les maîtriser. Toutefois, si jouer à ce petit jeu de la syntaxe ramassée permet d’économiser sur l’écriture, il ne permet certainement pas d’économiser sur la lecture, du moins tant que celui qui doit lire n’a pas appris à écrire pareillement.
Pour aider dans cet apprentissage, cet article évolutif se propose de recenser les syntaxes ramassées qu’un développeur peut rencontrer en lisant du code en Python (version 3.6.4), à condition qu’elles présentent une véritable utilité.
Pour l’heure, on trouvera des explications suivantes… :
L’article sera enrichi au fil des découvertes réalisées au fil de lectures. Ces mises à jour seront signalées.
Mise à jour du 08/03/2018 :
  • rappel de la typologie (et corrections !) ;
  • extraire une plage d’éléments d’une séquence (slicing).
Continuer la lecture de « Syntaxes avancées (car ramassées) en Python »
Syntaxes avancées (car ramassées) en Python

Paramètres et décorateurs de fonction en Python

Python permet d’écrire des fonctions comportant de nombreux paramètres qui peuvent avoir des mines des plus patibulaire, surtout si elles sont par ailleurs assorties de décorateurs. Par exemple :
def g (h):
	def k (prompt, *words, **complements):
		if complements['computer'] == 'Atari':
			complements['computer'] = 'Amiga'
		h (prompt, *words, **complements)
	return k
@g
def f (prompt, *words, **complements):
	for key, value in complements.items ():
		print (prompt + ':', ' '.join (words), value)
f ('HAL speaking', 'I', 'love', 'the', computer='Atari', drink='coffee')
HAL speaking: I love the Amiga
HAL speaking: I love the coffee
Il est important de ne pas se laisser abuser par cette apparente complexité. Maîtriser les différentes catégories de paramètres qu’il est possible d’utiliser est essentiel pour exploiter le potentiel de l’écriture de fonctions en Python au quotidien. Quant aux décorateurs, il est sans doute bien moins fréquent d’y avoir recours, mais comme ils peuvent se rencontrer, il est bon de savoir commment ils fonctionnent.
Continuer la lecture de « Paramètres et décorateurs de fonction en Python »
Paramètres et décorateurs de fonction en Python

Comment marche réellement la fonction super () de Python

La méthode super () de Python a inspiré un bon nombre d’explications. Toutefois, il apparaît qu’aussi sophistiquées qu’elles soient, elles sont toutes désespérement superficielles.
Je ne parle pas de celles qui le sont d’évidence, comme cette vidéo. L’auteur est bien gentil, mais sa présentation de super() se limite à assimiler la fonction à un moyen de déléguer un appel à la méthode __init__ () (par ailleurs, tout à fait improprement assimilée à un constructeur, comme si __new__ () n’existait pas…) surchargée dans une classe C à sa version dans une classe parent A. Autrement dit, à appeller A.__init__ () depuis C.__init__ (). Mais dans l’exemple, C hérite non seulement de A, mais aussi de B. Dès lors, les questions des commentateurs fusent : pourquoi B.__init__ () n’est-elle pas appelée ? Sincèrement, avant de publier une explication sur un sujet technique, son auteur devrait s’assurer qu’il maîtrise son sujet. Comme il le dit, « The super keyword is a little bit confusing in Python. It’s been confusing for decades now and it’s going to continue to be confusing as we move into the future. It’s just something that’s confusing ». Tu m’étonnes! surtout après avoir entendu sa prétendue explication…
Non. Je parle d’explications d’auteurs qui ont pignon sur rue, comme Python’s super() considered super! de Raymond Hettinger, à laquelle renvoie la documentation de super(), ou encore celle d’Alex Martelli, Anna Ravenscroft et Steve Holden dans leur Python in a Nutshell. Le moins qu’on puisse dire, c’est qu’on ne ressort pas illuminé de ces lectures. Sans doute, on comprend que super() permet de jouer avec le Method Resolution Order (MRO), mais quand a savoir exactement comment, c’est une autre affaire. Tout le monde se contente de terminer en recommandant d’utiliser systématiquement super() à tous les niveaux le hiérarchie des appels, et pour le reste renvoie sur l’algorithme C3, présenté comme abscons.
Bref, tout comme peu de personnes semblent avoir compris que JavaScript est un langage orienté objet à base de prototypes (et non de classes !), y’en a-t-il seulement qui ont compris comment la fonction super() de Python fonctionne vraiment ? Sérieusement, il y a de quoi nourrir de sérieuses inquiétudes quant au niveau d’exigence des développeurs désormais. Plus personne ne se donne la peine d’aller au fond des choses, ou quoi ?
On va donc arrêter de plaisanter, et expliquer sérieusement…
Continuer la lecture de « Comment marche réellement la fonction super () de Python »
Comment marche réellement la fonction super () de Python