Avoiding Windows backslash problems with Python’s raw strings

私は Unix 派ですが、私の Python クラスでは参加者は圧倒的に Windows を使っています。 必然的に、Python でファイルを操作する話になったとき、誰かがファイルへの完全なパスを使用してファイルを開きたいと思うでしょう。

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

しかし、生徒がファイルを開こうとすると、Pythonはファイルが存在しないことを示すエラーを出すのです!このような書き方をしてしまうのです。 つまり、

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

What’s the problem? これは非常に標準的な Python のように思えますが、そうではありませんか?

Python の文字列は通常文字を含んでいることを思い出してください。 これらの文字は通常印刷可能ですが、改行のような実際には印刷可能ではない文字を含めたい場合があります。 そのような場合、Python は (多くのプログラミング言語と同様に) 特殊文字を挿入する特別なコードを含んでいます。

最もよく知られている例は newline, aka ‘\n’, or ASCII 10 です。 Pythonの文字列に改行を挿入したい場合は、真ん中に’˶’sn’を入れて挿入することができます。 例えば:

s = 'abc\ndef\nghi'

この文字列を印刷すると:

>>> print(s)abcdefghi

コードの中でリテラルに’ \n’ を印刷したい場合はどうでしょう。 つまり、バックスラッシュの後に “n “を表示したい場合です。 文字列中の「♪」は1つのバックスラッシュ文字になります。 次の “n “は通常の文字になります。 例えば、

s = 'abc\ndef\nghi'

と言う場合、

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

この変換をガードする必要があることは結構知られていますね。 しかし、他にどのような文字が必要なのでしょうか? それは、多くの人が予想する以上に多いことがわかります。

  • A – alarm bell (ASCII 7)
  • B – backspace (ASCII
  • f – form feed
  • n – newline
  • r – carriage return
  • t – tab
  • v – carriage return
  • Thooo – character with octal value ooo
  • Thxhh – character with hex value hh
  • N{name} – Unicode character {name}
  • Thuxxxx – Unicode character with 16->Thoo
  • Thooxxxx – Unicode character with 16->Thoo ThooThooThoo。bit hex value xxxx
  • Uxxxxxx – Unicode character with 32-bit hex value xxxxxxxx

In my experience, これらのうちのいくつかを意図的に使用する可能性は極めて低いでしょう。 つまり、最後にフォームフィード文字を使う必要があったのはいつだったでしょうか? あるいは垂直タブは? それは、飲料水のために裏庭に井戸を掘った後、恐竜を職場に連れて行ったのとほぼ同じ日でしたね。 それは、これらの文字で使用されるバックスラッシュと Windows のパスで使用されるバックスラッシュの組み合わせが、避けられない、そしてイライラするバグを引き起こすからです。

Blog の冒頭で述べた、とても無邪気に見えるパスを覚えていますか?

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

それには “\a” 文字が含まれています。 つまり、これを印刷すると、

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

ほらね? “╱”が消えて、警鐘文字になってる。 運が良ければ…

では、どうすればいいのか? もちろんバックスラッシュを2重にする。 上に再現した表から、特殊文字になるものを2倍にすればいいのです。 でも、「♪」は特殊だけど、「♪」は特殊じゃないって、本当に覚えていますか?

ですから、私の一般的なルール、そして学生に言っていることは、Windows のパスでは常にバックスラッシュを2重にするべきだということです。 つまり、

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

It works!

But wait: 誰もパス名の中を本当に歩き回り、すべてのバックスラッシュを二重にしたくはないでしょう? もちろんそうではありません。

そこで、Python の生の文字列が役に立ちます。

  • what-you-see is what-you-get strings
  • automatically doubled backslashes in strings

いずれの方法でも、効果は同じです:すべてのバックスラッシュが2倍になるので、これらの厄介で奇妙な特殊文字のすべてが消えます。

あなたがすべきことは、開始引用符 (一重または二重) の前に “r” を置くことです:

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

“raw string” は実際にはまったく異なるタイプの文字列ではないことに注意してください。 これはPythonに文字列を入力する別の方法です。 確認すると、type(filename) は “str” のままですが、そのバックスラッシュはすべて2倍になります。

最下段です。 Windows を使っているなら、ハードコードされたパス名文字列はすべて生の文字列として書くべきでしょう。 たとえあなたがPythonのエキスパートであっても、経験から言って、時々この問題にぶつかることがあると思います。 そして、どんなに優秀な人でも、文字列の中にある迷子の “\f” を見つけるのは時間がかかり、イライラするものです。

PS: たしかに、Windows ユーザーは、我々 Unix ユーザーと同様にスラッシュを使用してこれを回避できます。 しかし、私の学生はこれを特に奇妙に見えると感じるので、汎用的な解決策とは思えません。

この記事を読みましたか? 私の無料の週刊ニュースレター「Better developers」を受信している 11,000 人以上の開発者に加わりましょう。 毎週月曜日には、ソフトウェア開発と Python に関するこのような記事が届きます:

コメントを残す

メールアドレスが公開されることはありません。