Undervika Windows backslash-problem med Pythons råa strängar

Jag är en Unix-kille, men deltagarna i mina Python-klasser använder till övervägande del Windows. När vi börjar prata om att arbeta med filer i Python är det oundvikligt att någon vill öppna en fil med hjälp av den fullständiga sökvägen till filen. Och det slutar med att de skriver något som liknar detta:

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

Men när mina elever försöker öppna filen upptäcker de att Python ger dem ett felmeddelande som visar att filen inte finns! Med andra ord skriver de:

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

Vad är problemet? Detta verkar vara ganska vanlig Python, eller hur?

Håll dig i minnet att strängar i Python normalt innehåller tecken. Dessa tecken är normalt utskrivbara, men det finns tillfällen då du vill inkludera ett tecken som egentligen inte är utskrivbart, t.ex. en nyrad. I dessa fall innehåller Python (liksom många programmeringsspråk) särskilda koder som infogar specialtecknet.

Det mest kända exemplet är newline, alias ”\n”, eller ASCII 10. Om du vill infoga en ny rad i din Pythonsträng kan du göra det med ’\n’ i mitten. Till exempel:

s = 'abc\ndef\nghi'

När vi skriver ut strängen ser vi:

>>> print(s)abcdefghi

Hur blir det om du vill skriva ut en bokstavlig ’\n’ i din kod? Det vill säga att du vill ha ett backslash följt av ett ”n”? Då måste du fördubbla backslashet: ”\\” i en sträng resulterar i ett enkelt backslashtecken. Det efterföljande ”n” kommer då att vara normalt. Till exempel:

s = 'abc\ndef\nghi'

När vi säger:

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

Det är ganska välkänt att man måste akta sig för denna översättning när man arbetar med \n. Men vilka andra tecken kräver det? Det visar sig att det är fler än vad många kanske förväntar sig:

  • \a – väckarklocka (ASCII 7)
  • \b – backspace (ASCII
  • \f – form feed
  • \n – newline
  • \r – carriage return
  • \t – tab
  • \v – vertikal tabb
  • \ooo – tecken med oktalvärde ooo
  • \xhh – tecken med hexatalvärde hh
  • \N{name} – Unicode-tecken {name}
  • \uxxxx – Unicode-tecken med 16-bitars hexatekniskt värde xxxx
  • \Uxxxxxxxxxxxx – Unicode-tecken med 32-bitars hexatekniskt värde xxxxxxxx

I min erfarenhet, är det ytterst osannolikt att du använder några av dessa med flit. Jag menar, när var sista gången du behövde använda ett form feed-tecken? Eller en vertikal tabb? Jag vet – det var ungefär samma dag som du körde din dinosaurien till jobbet, efter att ha grävt en brunn på din bakgård för att få dricksvatten.

Men nästan varje gång jag undervisar i Python – vilket är, varje dag – stöter någon i min klass på ett av dessa tecken av misstag. Det beror på att kombinationen av de backslashes som används av dessa tecken och de backslashes som används i Windows-stigar skapar oundvikliga och frustrerande buggar.

Håller du ihåg den där stigen som jag nämnde högst upp i blogginlägget och som verkar så oskyldig?

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

Den innehåller ett ”\a”-tecken. Det betyder att när vi skriver ut det:

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

Se? \a” är borta och har ersatts av ett alarmklocka-tecken. Om du har tur.

Så, vad kan vi göra åt detta? Fördubbla backslashes, förstås. Du behöver bara fördubbla de som skulle förvandlas till specialtecken, från tabellen som jag har återgett ovan: Men kom igen, är det verkligen troligt att du kommer ihåg att ”\f” är ett specialtecken, men att ”\g” inte är det? Förmodligen inte.

Så min allmänna regel, och vad jag säger till mina elever, är att de alltid bör fördubbla backslashes i sina Windows-sökvägar. Med andra ord:

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

Det fungerar!

Men vänta: Ingen vill väl verkligen gå igenom sina sökvägar och dubbla varje backslash? Självklart inte.

Det är där Pythons råa strängar kan hjälpa till. Jag tänker på raw strings på två olika sätt:

  • Vad-du-ser-är-vad-du-får-strängar
  • automatiskt fördubblade backslashes i strängar

Hursomhelst är effekten densamma: Alla backslashes fördubblas, så alla dessa irriterande och konstiga specialtecken försvinner. Vilket är bra när du arbetar med Windows-sökvägar.

Det enda du behöver göra är att sätta ett ”r” före de inledande citattecken (enkla eller dubbla):

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

Bemärk att en ”rå sträng” egentligen inte alls är en annan typ av sträng. Det är bara ett annat sätt att skriva in en sträng i Python. Om du kontrollerar, kommer type(filnamn) fortfarande att vara ”str”, men dess backslashes kommer alla att fördubblas.

Bottom line: Om du använder Windows bör du bara skriva alla dina hårt kodade filnamnssträngar som råa strängar. Även om du är Python-expert kan jag av erfarenhet säga att du kommer att stöta på det här problemet ibland. Och även för den bästa av oss kan det vara tidskrävande och frustrerande att hitta det där ”\f” i en sträng.

PS: Ja, det är sant att Windows-användare kan komma runt detta genom att använda snedstreck framåt, som vi Unix-folk gör. Men mina elever tycker att detta ser särskilt konstigt ut, och därför ser jag det inte som en allmän lösning.

Gillade du den här artikeln? Gå med mer än 11 000 andra utvecklare som får mitt gratis veckovisa nyhetsbrev ”Bättre utvecklare”. Varje måndag får du en artikel som denna om mjukvaruutveckling och Python:

Lämna ett svar

Din e-postadress kommer inte publiceras.