Avoiding Windows backslash problems with Python’s raw strings

Jestem facetem od Uniksa, ale uczestnicy moich zajęć z Pythona w przeważającej większości używają Windowsa. Nieuchronnie, kiedy zaczynamy rozmawiać o pracy z plikami w Pythonie, ktoś będzie chciał otworzyć plik używając pełnej ścieżki do niego. I skończy się na napisaniu czegoś takiego:

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

Ale kiedy moi studenci próbują otworzyć plik, odkrywają, że Python daje im błąd, wskazując, że plik nie istnieje! Innymi słowy, piszą:

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

W czym problem? Wygląda to na całkiem standardowy Python, prawda?

Pamiętaj, że łańcuchy w Pythonie zwykle zawierają znaki. Te znaki są zwykle drukowalne, ale zdarzają się sytuacje, gdy chcesz dołączyć znak, który nie jest drukowalny, taki jak nowa linia. W takich przypadkach Python (jak wiele języków programowania) zawiera specjalne kody, które wstawiają znak specjalny.

Najbardziej znanym przykładem jest nowa linia, aka „n”, lub ASCII 10. Jeśli chcesz wstawić nową linię do swojego łańcucha w Pythonie, możesz to zrobić z 'n’ w środku. Na przykład:

s = 'abc\ndef\nghi'

Gdy wydrukujemy ten łańcuch, zobaczymy:

>>> print(s)abcdefghi

A co, jeśli chcesz wydrukować dosłowne 'n’ w swoim kodzie? To znaczy, chcesz backslash, a następnie „n”? Wtedy będziesz musiał podwoić odwrotny ukośnik: „n” w łańcuchu spowoduje pojedynczy znak odwrotnego ukośnika. Następujące „n” będzie wtedy normalne. Na przykład:

s = 'abc\ndef\nghi'

Gdy powiemy:

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

Jest dość dobrze znane, że trzeba się wystrzegać tego tłumaczenia, gdy pracujemy z „n”. Ale jakie inne znaki tego wymagają? Okazuje się, że więcej niż wiele osób mogłoby się spodziewać:

  • a – alarm bell (ASCII 7)
  • b – backspace (ASCII
  • f – form feed
  • n – newline
  • r – carriage return
  • t – tab
  • v – vertical tab
  • ooo – znak o wartości ósemkowej ooo
  • xhh – znak o wartości heksadecymalnej hh
  • N{name} – znak Unicode {name}
  • uxxxx – znak Unicode o wartości 16-bitową wartością heksadecymalną xxxx
  • Uxxxxxx – znak Unicode z 32-bitową wartością heksadecymalną xxxxxxxx

W moim doświadczeniu, jest bardzo mało prawdopodobne, abyś używał niektórych z nich celowo. Chodzi mi o to, kiedy ostatnio potrzebowałeś użyć znaku form feed? Albo pionowego tabulatora? Wiem – to był mniej więcej ten sam dzień, w którym zawiozłeś swojego dinozaura do pracy, po wykopaniu studni na swoim podwórku w celu uzyskania wody pitnej.

Ale prawie za każdym razem, gdy uczę Pythona – czyli codziennie – ktoś w mojej klasie wpada na jeden z tych znaków przez pomyłkę. Dzieje się tak dlatego, że kombinacja ukośników odwrotnych używanych przez te znaki oraz ukośników odwrotnych używanych w ścieżkach systemu Windows tworzy nieuniknione i frustrujące błędy.

Pamiętasz tę ścieżkę, o której wspomniałem na początku wpisu na blogu, a która wydaje się taka niewinna?

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

Zawiera ona znak „ą”. Co oznacza, że kiedy ją wydrukujemy:

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

Widzisz? Znak „™a” zniknie, zastąpiony przez znak dzwonka alarmowego. Jeśli masz szczęście.

Więc, co możemy z tym zrobić? Podwoić odwrotne ukośniki, oczywiście. Musisz tylko podwoić te, które zostałyby zamienione na znaki specjalne, z tabeli, którą odtworzyłem powyżej: Ale daj spokój, czy naprawdę jesteś skłonny zapamiętać, że „f” jest specjalne, ale „g” nie? Prawdopodobnie nie.

Więc moja ogólna zasada, i to co mówię moim studentom, jest taka, że powinni oni zawsze podwajać backslashe w swoich ścieżkach Windows. Innymi słowy:

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

To działa!

Ale czekaj: Nikt nie chce naprawdę przedzierać się przez swoje nazwy ścieżek, podwajając każdy odwrotny ukośnik, prawda? Oczywiście, że nie.

W tym właśnie miejscu mogą pomóc surowe ciągi Pythona. Myślę o nieprzetworzonych łańcuchach na dwa różne sposoby:

  • what-you-see-is-what-you-get strings
  • automatycznie podwajane backslashe w łańcuchach

W każdym razie, efekt jest taki sam: wszystkie backslashe są podwajane, więc wszystkie te kłopotliwe i dziwne znaki specjalne znikają. Co jest świetne, gdy pracujesz ze ścieżkami Windows.

Wszystko, co musisz zrobić, to umieścić „r” przed cudzysłowami otwierającymi (pojedynczymi lub podwójnymi):

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

Zauważ, że „surowy łańcuch” nie jest tak naprawdę innym typem łańcucha w ogóle. Jest to po prostu inny sposób na wprowadzenie łańcucha do Pythona. Jeśli sprawdzisz, type(filename) nadal będzie „str”, ale jego backslashe będą podwojone.

Dolna linia: Jeśli używasz systemu Windows, to powinieneś po prostu napisać wszystkie swoje twardo zakodowane ciągi nazw plików jako surowe ciągi. Nawet jeśli jesteś ekspertem Pythona, mogę ci powiedzieć z doświadczenia, że czasami natkniesz się na ten problem. I nawet dla najlepszych z nas, znalezienie tego zabłąkanego „f” w łańcuchu może być czasochłonne i frustrujące.

PS: Tak, to prawda, że użytkownicy Windows mogą to obejść, używając ukośników w przód, tak jak my, ludzie Unixa. Ale moi studenci uważają, że wygląda to szczególnie dziwnie, więc nie uważam tego za rozwiązanie uniwersalne.

Cieszył Cię ten artykuł? Dołącz do ponad 11 000 innych programistów, którzy otrzymują mój darmowy, cotygodniowy biuletyn „Lepsi programiści”. W każdy poniedziałek otrzymasz artykuł, taki jak ten, na temat tworzenia oprogramowania i Pythona:

.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.