Evitare i problemi di backslash di Windows con le stringhe grezze di Python

Sono un tipo da Unix, ma i partecipanti ai miei corsi di Python usano prevalentemente Windows. Inevitabilmente, quando si parla di lavorare con i file in Python, qualcuno vorrà aprire un file usando il percorso completo del file. E finirà per scrivere qualcosa come questo:

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

Ma quando i miei studenti cercano di aprire il file, scoprono che Python dà loro un errore, indicando che il file non esiste! In altre parole, scrivono:

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

Qual è il problema? Questo sembra Python abbastanza standard, no?

Ricordate che le stringhe in Python normalmente contengono caratteri. Quei caratteri sono normalmente stampabili, ma ci sono momenti in cui vuoi includere un carattere che non è veramente stampabile, come un newline. In questi casi, Python (come molti linguaggi di programmazione) include codici speciali che inseriranno il carattere speciale.

L’esempio più noto è il newline, detto ‘\n’, o ASCII 10. Se volete inserire un newline nella vostra stringa Python, allora potete farlo con ‘\n’ nel mezzo. Per esempio:

s = 'abc\ndef\nghi'

Quando stampiamo la stringa, vedremo:

>>> print(s)abcdefghi

E se volete stampare un ‘\n’ letterale nel vostro codice? Cioè, volete un backslash, seguito da una “n”? Allora dovrai raddoppiare il backslash:Il “\n” in una stringa risulterà in un singolo carattere backslash. La “n” seguente sarà quindi normale. Per esempio:

s = 'abc\ndef\nghi'

Quando diciamo:

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

È abbastanza noto che bisogna fare attenzione a questa traduzione quando si lavora con \n. Ma quali altri caratteri lo richiedono? A quanto pare, più di quanto molti potrebbero aspettarsi:

  • \a – campanello d’allarme (ASCII 7)
  • \b – backspace (ASCII
  • \f – form feed
  • \n – newline
  • \r – carriage return
  • \t – tab
  • \v – verticale
  • \ooo – carattere con valore ottale ooo
  • \xhh – carattere con valore esadecimale hh
  • \N{nome} – carattere Unicode {nome}
  • \uxxxx – carattere Unicode con valore esadecimale 16-valore esadecimale a 16 bit xxxx
  • Uxxxxxxxx – Carattere Unicode con valore esadecimale a 32 bit xxxxxxxx

Nella mia esperienza, è estremamente improbabile che tu usi alcuni di questi di proposito. Voglio dire, quando è stata l’ultima volta che avete avuto bisogno di usare un carattere di avanzamento della forma? O una tabulazione verticale? Lo so – è stato più o meno lo stesso giorno in cui avete guidato il vostro dinosauro al lavoro, dopo aver scavato un pozzo nel vostro cortile per l’acqua potabile.

Ma quasi ogni volta che insegno Python – che è, ogni giorno – qualcuno nella mia classe si imbatte in uno di questi caratteri per errore. Questo perché la combinazione dei backslash usati da questi caratteri e i backslash usati nei percorsi di Windows crea inevitabili, e frustranti, bug.

Ricordate quel percorso che ho menzionato all’inizio del post, che sembra così innocente?

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

Contiene un carattere “\a”. Il che significa che quando lo stampiamo:

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

Vedi? La “\a” non c’è più, sostituita da un carattere di campanello d’allarme. Se siete fortunati.

Quindi, cosa possiamo fare? Raddoppiare le backslash, naturalmente. Basta raddoppiare quelle che verrebbero trasformate in caratteri speciali, dalla tabella che ho riprodotto sopra: Ma andiamo, è davvero probabile che vi ricordiate che “\f” è speciale, ma “\g” no? Probabilmente no.

Quindi la mia regola generale, e quello che dico ai miei studenti, è che dovrebbero sempre raddoppiare le backslash nei loro percorsi Windows. In altre parole:

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

Funziona!

Ma aspetta: nessuno vuole davvero guadare i propri nomi di percorso, raddoppiando ogni backslash, vero? Certo che no.

Ecco dove le stringhe grezze di Python possono aiutare. Penso alle stringhe grezze in due modi diversi:

  • le stringhe che si vedono sono quelle che si ottengono
  • le backslash raddoppiate automaticamente nelle stringhe

In entrambi i casi, l’effetto è lo stesso: tutte le backslash sono raddoppiate, quindi tutti questi fastidiosi e strani caratteri speciali spariscono. Il che è ottimo quando si lavora con i percorsi di Windows.

Tutto quello che dovete fare è mettere una “r” prima degli apici di apertura (singoli o doppi):

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

Nota che una “stringa grezza” non è affatto un tipo diverso di stringa. È solo un altro modo di inserire una stringa in Python. Se controllate, type(filename) sarà ancora “str”, ma le sue backslash saranno tutte raddoppiate.

In fondo: Se state usando Windows, allora dovreste semplicemente scrivere tutte le vostre stringhe di percorso hard-coded come stringhe grezze. Anche se siete esperti di Python, posso dirvi per esperienza che a volte vi imbatterete in questo problema. E anche per i migliori di noi, trovare quel “\f” vagante in una stringa può essere lungo e frustrante.

PS: Sì, è vero che gli utenti Windows possono aggirare questo problema usando le barre in avanti, come facciamo noi di Unix. Ma i miei studenti lo trovano particolarmente strano, e quindi non lo vedo come una soluzione generale.

Ti è piaciuto questo articolo? Unisciti a più di 11.000 altri sviluppatori che ricevono la mia newsletter settimanale gratuita “Better developers”. Ogni lunedì, riceverai un articolo come questo sullo sviluppo di software e Python:

.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.