Undergå Windows backslash-problemer med Pythons rå strenge

Jeg er en Unix-fyr, men deltagerne i mine Python-klasser bruger i overvejende grad Windows. Det er uundgåeligt, at når vi kommer til at tale om at arbejde med filer i Python, vil nogen ønske at åbne en fil ved hjælp af den komplette sti til filen. Og de vil ende med at skrive noget som dette:

filename = 'c:\abc\def\ghi.txt'

Men når mine elever forsøger at åbne filen, opdager de, at Python giver dem en fejl, der angiver, at filen ikke eksisterer! Med andre ord skriver de:

for one_line in open(filename): print(one_line)

Hvad er problemet? Det virker som ret standard Python, ikke?

Husk, at strings i Python normalt indeholder tegn. Disse tegn er normalt printbare, men der er tidspunkter, hvor du ønsker at inkludere et tegn, der ikke rigtig er printbart, f.eks. en newline. I disse tilfælde indeholder Python (ligesom mange programmeringssprog) særlige koder, der indsætter det særlige tegn.

Det mest kendte eksempel er newline, også kendt som “\n” eller ASCII 10. Hvis du vil indsætte en newline i din Python-streng, så kan du gøre det med ‘\n’ i midten. For eksempel:

s = 'abc\ndef\nghi'

Når vi udskriver strengen, vil vi se:

>>> print(s)abcdefghi

Hvad sker der, hvis du vil udskrive et bogstaveligt ‘\n’ i din kode? Det vil sige, at du ønsker en skråstreg, efterfulgt af et “n”? Så skal du fordoble backslash’en: “\\” i en streng resulterer i et enkelt backslash-tegn. Det efterfølgende “n” vil derefter være normalt. For eksempel:

s = 'abc\ndef\nghi'

Når vi siger:

>>> print(s)abc\ndef\nghi

Det er ret velkendt, at man skal passe på denne oversættelse, når man arbejder med \n. Men hvilke andre tegn kræver det? Det viser sig, at der er flere, end mange måske forventer:

  • \a – alarmklokke (ASCII 7)
  • \b – backspace (ASCII
  • \f – form feed
  • \n – newline
  • \r – carriage return
  • \t – tab
  • \v – lodret tabulator
  • \ooo – tegn med oktalværdi ooo
  • \xhh – tegn med hexalværdi hh
  • \N{name} – Unicode-tegn {name}
  • \uxxxx – Unicode-tegn med 16-bit hex-værdi xxxx
  • \Uxxxxxxxxxxxx – Unicode-tegn med 32-bit hex-værdi xxxxxxxx

I min erfaring, er det yderst usandsynligt, at du vil bruge nogle af disse med vilje. Jeg mener, hvornår har du sidst haft brug for at bruge et form feed-tegn? Eller en lodret tabulator? Jeg ved det godt – det var nogenlunde samme dag, som du kørte din din dinosaur på arbejde efter at have gravet en brønd i din baghave til drikkevand.

Men næsten hver gang jeg underviser i Python – hvilket er, hver dag – er der nogen i min klasse, der støder på et af disse tegn ved en fejltagelse. Det skyldes, at kombinationen af de skråstreger, der bruges af disse tegn, og de skråstreger, der bruges i Windows-stier, giver uundgåelige og frustrerende fejl.

Huskede du den sti, jeg nævnte øverst i blogindlægget, som virker så uskyldig?

filename = 'c:\abc\def\ghi.txt'

Den indeholder et “\a”-tegn. Hvilket betyder, at når vi udskriver det:

>>> print(filename)c:bc\def\ghi.txt

Se? “\a”-tegnet er væk og erstattet af et alarmklokke-tegn. Hvis du er heldig.

Så, hvad kan vi gøre ved dette? Fordoble backslashes, selvfølgelig. Du behøver kun at fordoble dem, der ville blive omdannet til specialtegn, fra den tabel, jeg har gengivet ovenfor: Men helt ærligt, er det virkelig sandsynligt, at du kan huske, at “\f” er et specialtegn, men at “\g” ikke er det? Sandsynligvis ikke.

Så min generelle regel, og hvad jeg fortæller mine studerende, er, at de altid skal fordoble backslashes i deres Windows-stier. Med andre ord:

>>> filename = 'c:\abc\def\ghi.txt'>>> print(filename)c:\abc\def\ghi.txt

Det virker!

Men vent: Ingen ønsker virkelig at vade gennem deres pathnames og fordoble hver backslash, gør de? Selvfølgelig ikke.

Det er her Pythons rå strenge kan hjælpe. Jeg tænker på raw strings på to forskellige måder:

  • hvad-du-siger-er-hvad-du-får-strenge
  • automatisk fordoblede backslashes i strings

Og på begge måder er effekten den samme: Alle backslashes fordobles, så alle disse irriterende og underlige specialtegn forsvinder. Hvilket er fantastisk, når du arbejder med Windows-stier.

Det eneste, du skal gøre, er at sætte et “r” foran de indledende anførselstegn (enkelt eller dobbelt):

>>> filename = r'c:\abc\def\ghi.txt'>>> print(filename)c:\abc\def\ghi.txt

Bemærk, at en “rå streng” i virkeligheden slet ikke er en anden type streng. Det er bare en anden måde at indtaste en streng i Python på. Hvis du kontrollerer det, vil type(filnavn) stadig være “str”, men dens backslashes vil alle være fordoblet.

Sidste linje: Hvis du bruger Windows, skal du bare skrive alle dine hårdtkodede pathname-strenge som råstrenge. Selv om du er Python-ekspert, kan jeg af erfaring fortælle dig, at du vil støde på dette problem nogle gange. Og selv for de bedste af os kan det være tidskrævende og frustrerende at finde det vildfarne “\f” i en streng.

PS: Ja, det er rigtigt, at Windows-brugere kan omgå dette ved at bruge forward slashes, ligesom vi Unix-folk gør. Men mine studerende synes, at det ser særligt mærkeligt ud, og derfor ser jeg det ikke som en generel løsning.

Nydt du denne artikel? Slut dig til mere end 11.000 andre udviklere, der modtager mit gratis, ugentlige nyhedsbrev “Bedre udviklere”. Hver mandag får du en artikel som denne om softwareudvikling og Python:

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.