Le sourire du jour
mardi 4 mars 2014 à 11:29Je me baladais dans le code source de path.py, et je suis tombé sur l’auteur essayant de résoudre le problème suivant :
“Soit une chaine ‘mode’ représentant le mode d’ouverture du fichier, détecter si le fichier est demandé à être ouvert en écriture et dans ce cas lever une exception”
L’implémentation naïve serait:
for letter in mode: if letter in 'wa+': raise ValueError('Only read-only file modes can be used')
Une implémentation un peu plus classe serait :
if any(letter for letter in mode if letter in 'wa+'): raise ValueError('Only read-only file modes can be used')
Mais l’auteur a choisit d’utiliser les sets, qui sont exactement fait pour ça. Et la solution est simple et élégante:
if set(mode).intersection('wa+'): raise ValueError('Only read-only file modes can be used')
Je sais, il m’en faut pas grand chose pour être heureux.
Edit: explication demandée en comments :)
Un set
permet de prendre n’importe quel itérable, et créer un ensemble avec. Il est capable de faire toutes les opérations ensemblistes (union, différence, etc) entre lui-même et un autre itérable.
Dans notre cas, si le mode contient un flag qui implique l’écriture, voici ce que ça donne en détails :
>>> mode = 'wb' >>> set_de_mode = set(mode) >>> set_de_mode set([u'b', u'w']) >>> set_de_mode.intersection('wa+') set([u'w'])
On se retrouve donc avec un élément dans le set
résultant de l’intersection. Un set
non vide a une valeur True
dans un contexte booléen en Python, donc la conditionif set(mode).intersection('wa+'):
sera remplie.
A l’inverse, si il n’y a pas de flag qui implique l’écriture :
>>> set('r').intersection('wa+') set([])
On obtient un set
vide, qui vaut False
dans un contexte booléen.
Tout ceci marche car les chaînes de caractères sont itérables en Python, et que les sets acceptent n’importe quel itérable. Vive le duck typing.