Ik ben een Unix-man, maar de deelnemers aan mijn Python-lessen maken overwegend gebruik van Windows. Wanneer we het hebben over het werken met bestanden in Python, is het onvermijdelijk dat iemand een bestand wil openen met het volledige pad naar het bestand. En dan schrijven ze iets als dit:
filename = 'c:\abc\def\ghi.txt'
Maar wanneer mijn studenten het bestand proberen te openen, ontdekken ze dat Python hen een fout geeft, die aangeeft dat het bestand niet bestaat! Met andere woorden, ze schrijven:
for one_line in open(filename): print(one_line)
Wat is het probleem? Dit lijkt een vrij standaard Python, niet?
Houd in gedachten dat strings in Python normaal karakters bevatten. Die karakters zijn normaal gesproken afdrukbaar, maar er zijn momenten dat je een karakter wilt opnemen dat niet echt afdrukbaar is, zoals een newline. In die gevallen bevat Python (net als veel programmeertalen) speciale codes om het speciale teken in te voegen.
Het bekendste voorbeeld is de newline, ook wel ‘\n’ genoemd, of ASCII 10. Als u een newline in uw Python string wilt invoegen, dan kunt u dat doen met ‘\n’ in het midden. Bijvoorbeeld:
s = 'abc\ndef\nghi'
Wanneer we de string afdrukken, zien we:
>>> print(s)abcdefghi
Wat nu als je een letterlijke ‘\n’ in je code wilt afdrukken? Dat wil zeggen, je wilt een backslash, gevolgd door een “n”? Dan moet je de backslash verdubbelen:De “n” in een string zal resulteren in een enkel backslash karakter. De volgende “n” is dan normaal. Bijvoorbeeld:
s = 'abc\ndef\nghi'
Wanneer we zeggen:
>>> print(s)abc\ndef\nghi
Het is vrij algemeen bekend dat je moet waken voor deze vertaling wanneer je werkt met “n”. Maar welke andere karakters hebben dit nodig? Het blijkt, meer dan veel mensen zouden verwachten:
- a – alarmbel (ASCII 7)
- b – backspace (ASCII
- f – form feed
- n – newline
- r – carriage return
- t – tab
- v – verticaal tab
- ooo – teken met octale waarde ooo
- xhh – teken met hex waarde hh
- N{name} – Unicode teken {name}
- uxxxx – Unicode teken met 16-bit hex waarde xxxx
- Uxxxxxxxx – Unicode karakter met 32-bit hex waarde xxxxxxxx
In mijn ervaring, is het zeer onwaarschijnlijk dat je sommige van deze met opzet gebruikt. Ik bedoel, wanneer was de laatste keer dat je een form feed karakter moest gebruiken? Of een verticale tab? Ik weet het – het was ongeveer dezelfde dag dat je je dinosaurus naar het werk reed, na het graven van een put in je achtertuin voor drinkwater.
Maar bijna elke keer dat ik Python les geef – en dat is, elke dag – loopt iemand in mijn klas per ongeluk tegen een van deze tekens aan. Dat komt omdat de combinatie van de backslashes gebruikt door deze tekens en de backslashes gebruikt in Windows paden zorgt voor onvermijdelijke, en frustrerende, bugs.
Herken je dat pad nog dat ik bovenaan de blogpost noemde, dat zo onschuldig lijkt?
filename = 'c:\abc\def\ghi.txt'
Het bevat een “\a”-teken. Wat betekent dat als we het printen:
>>> print(filename)c:bc\def\ghi.txt
Zie je? De “\a” is weg, vervangen door een alarmbel teken. Als je geluk hebt.
Dus, wat kunnen we hieraan doen? Verdubbel de backslashes, natuurlijk. U hoeft alleen die te verdubbelen die in speciale tekens zouden worden omgezet, uit de tabel die ik hierboven heb weergegeven: Maar kom op, is het echt waarschijnlijk dat u onthoudt dat “\f” speciaal is, maar “\g” niet? Waarschijnlijk niet.
Dus mijn algemene regel, en wat ik mijn studenten vertel, is dat ze altijd de backslashes in hun Windows paden moeten verdubbelen. Met andere woorden:
>>> filename = 'c:\abc\def\ghi.txt'>>> print(filename)c:\abc\def\ghi.txt
Het werkt!
Maar wacht: Niemand wil echt door hun padnamen waden, elke backslash verdubbelen, toch? Natuurlijk niet.
Dat is waar Python’s raw strings kunnen helpen. Ik denk aan raw strings op twee verschillende manieren:
- what-you-see-is-what-you-get strings
- automatisch verdubbelde backslashes in strings
Het effect is hoe dan ook hetzelfde: alle backslashes worden verdubbeld, dus al die vervelende en vreemde speciale tekens gaan weg.
Het enige wat u hoeft te doen is een “r” voor de aanhalingstekens (enkel of dubbel) te zetten:
>>> filename = r'c:\abc\def\ghi.txt'>>> print(filename)c:\abc\def\ghi.txt
Merk op dat een “raw string” niet echt een ander type string is. Het is gewoon een andere manier om een string in Python in te voeren. Als je het controleert, zal type(bestandsnaam) nog steeds “str” zijn, maar de backslashes zullen allemaal verdubbeld zijn.
Onderste regel: Als je Windows gebruikt, dan moet je gewoon al je hard-coded padnaam strings als raw strings schrijven. Zelfs als je een Python expert bent, kan ik je uit ervaring vertellen dat je dit probleem soms zult tegenkomen. En zelfs voor de beste onder ons, kan het vinden van die verdwaalde “\f” in een string tijdrovend en frustrerend zijn.
PS: Ja, het is waar dat Windows gebruikers dit kunnen omzeilen door forward slashes te gebruiken, zoals wij Unix mensen doen. Maar mijn studenten vinden dit er bijzonder vreemd uitzien, en dus zie ik het niet als een oplossing voor algemeen gebruik.
Vond je dit artikel leuk? Sluit je aan bij meer dan 11.000 andere ontwikkelaars die mijn gratis, wekelijkse nieuwsbrief “Betere ontwikkelaars” ontvangen. Elke maandag krijg je een artikel als dit over software-ontwikkeling en Python: