Je suis un gars Unix, mais les participants à mes cours de Python utilisent en grande majorité Windows. Inévitablement, lorsque nous en arrivons à parler du travail avec des fichiers en Python, quelqu’un voudra ouvrir un fichier en utilisant le chemin complet du fichier. Et il finira par écrire quelque chose comme ceci:
filename = 'c:\abc\def\ghi.txt'
Mais lorsque mes étudiants essaient d’ouvrir le fichier, ils découvrent que Python leur donne une erreur, indiquant que le fichier n’existe pas ! En d’autres termes, ils écrivent :
for one_line in open(filename): print(one_line)
Quel est le problème ? Cela semble être du Python assez standard, non ?
Rappellez-vous que les chaînes de caractères en Python contiennent normalement des caractères. Ces caractères sont normalement imprimables, mais il y a des moments où vous voulez inclure un caractère qui n’est pas vraiment imprimable, comme une nouvelle ligne. Dans ces cas, Python (comme de nombreux langages de programmation) inclut des codes spéciaux qui insèrent le caractère spécial.
L’exemple le plus connu est la nouvelle ligne, alias ‘\n’, ou ASCII 10. Si vous voulez insérer une nouvelle ligne dans votre chaîne Python, alors vous pouvez le faire avec ‘\n’ au milieu. Par exemple :
s = 'abc\ndef\nghi'
Lorsque nous imprimons la chaîne de caractères, nous voyons :
>>> print(s)abcdefghi
Que faire si vous voulez imprimer un ‘\n’ littéral dans votre code ? C’est-à-dire que vous voulez une barre oblique inversée, suivie d’un « n » ? Dans ce cas, vous devrez doubler la barre oblique inversée :Le « \\ » dans une chaîne de caractères se traduira par un seul caractère oblique inversé. Le « n » suivant sera alors normal. Par exemple:
s = 'abc\ndef\nghi'
Quand on dit:
>>> print(s)abc\ndef\nghi
Il est assez bien connu que vous devez vous prémunir de cette traduction lorsque vous travaillez avec l’\n. Mais quels autres caractères l’exigent ? Il s’avère qu’il y en a plus que ce à quoi beaucoup de gens pourraient s’attendre :
- \a – sonnerie d’alarme (ASCII 7)
- \b – retour arrière (ASCII
- \f – saut de page
- \n – nouvelle ligne
- \r – retour chariot
- \t – tabulation
- \v – tabulation verticale
- \ooo – caractère avec valeur octale ooo
- \xhh – caractère avec valeur hexagonale hh
- \N{name} – caractère Unicode {nom}
- \uxxxx – caractère Unicode avec valeur hexagonale 16-bit xxxx
- \Uxxxxxxxx – Caractère Unicode avec une valeur hexagonale de 32 bits xxxxxxxx
Dans mon expérience, il est extrêmement peu probable que vous utilisiez certains d’entre eux volontairement. Je veux dire, à quand remonte la dernière fois où vous avez eu besoin d’utiliser un caractère de saut de page ? Ou une tabulation verticale ? Je sais – c’était à peu près le même jour où vous avez conduit votre dinosaure au travail, après avoir creusé un puits dans votre jardin pour avoir de l’eau potable.
Mais presque chaque fois que j’enseigne Python – c’est-à-dire, chaque jour – quelqu’un dans ma classe se heurte à l’un de ces caractères par erreur. C’est parce que la combinaison des barres obliques inversées utilisées par ces caractères et des barres obliques inversées utilisées dans les chemins d’accès de Windows donne lieu à des bogues inévitables, et frustrants.
Souvenez-vous de ce chemin d’accès dont j’ai parlé en haut du billet de blog, qui semble si innocent ?
filename = 'c:\abc\def\ghi.txt'
Il contient un caractère « \a ». Ce qui signifie que lorsque nous l’imprimons:
>>> print(filename)c:bc\def\ghi.txt
Vous voyez ? Le « \a » a disparu, remplacé par un caractère de sonnerie. Si vous êtes chanceux.
Alors, que pouvons-nous faire à ce sujet ? Doublez les barres obliques inversées, bien sûr. Il suffit de doubler ceux qui seraient transformés en caractères spéciaux, à partir du tableau que j’ai reproduit ci-dessus : Mais allez, êtes-vous vraiment susceptible de vous souvenir que « \f » est spécial, mais que « \g » ne l’est pas ? Probablement pas.
Donc ma règle générale, et ce que je dis à mes étudiants, est qu’ils doivent toujours doubler les antislashs dans leurs chemins Windows. En d’autres termes :
>>> filename = 'c:\abc\def\ghi.txt'>>> print(filename)c:\abc\def\ghi.txt
Ca marche !
Mais attendez : personne ne veut vraiment patauger dans ses noms de chemin, en doublant chaque barre oblique inverse, n’est-ce pas ? Bien sûr que non.
C’est là que les chaînes brutes de Python peuvent aider. Je pense aux chaînes brutes de deux façons différentes :
- ce que vous voyez est ce que vous obtenez
- les backslashes doublés automatiquement dans les chaînes
Dans les deux cas, l’effet est le même : tous les backslashes sont doublés, donc tous ces caractères spéciaux embêtants et bizarres disparaissent. Ce qui est génial lorsque vous travaillez avec des chemins Windows.
Tout ce que vous avez à faire est de mettre un « r » avant les guillemets ouvrants (simples ou doubles):
>>> filename = r'c:\abc\def\ghi.txt'>>> print(filename)c:\abc\def\ghi.txt
Notez qu’une « chaîne brute » n’est pas vraiment un type différent de chaîne du tout. C’est juste une autre façon d’entrer une chaîne dans Python. Si vous vérifiez, type(filename) sera toujours « str », mais ses backslashes seront tous doublés.
Ligne de fond : Si vous utilisez Windows, alors vous devriez juste écrire toutes vos chaînes de noms de chemin codées en dur comme des chaînes brutes. Même si vous êtes un expert de Python, je peux vous dire par expérience que vous vous heurterez parfois à ce problème. Et même pour les meilleurs d’entre nous, trouver ce « \f » égaré dans une chaîne peut prendre du temps et être frustrant.
PS : Oui, il est vrai que les utilisateurs de Windows peuvent contourner ce problème en utilisant des slashs avant, comme nous, les gens d’Unix, le faisons. Mais mes étudiants trouvent que cela a un aspect particulièrement étrange, et je ne vois donc pas cela comme une solution générale.
Vous avez aimé cet article ? Rejoignez plus de 11 000 autres développeurs qui reçoivent gratuitement ma lettre d’information hebdomadaire « Better developers ». Chaque lundi, vous recevrez un article comme celui-ci sur le développement logiciel et Python :
.