python3.6で導入されるf文字列はformatメソッドとは違う

pythonで文字列フォーマットをするときには今のところ二通り方法があって、pythonには珍しく(?)統一されていない感じになっています。 で、python3.6では更に新しい方法が追加されるらしいです。 軽く使ってみたのですが、微妙にformatメソッドと違ったりして不思議な感じなので、軽くメモ。 記事執筆時点での開発版の仕様を元にしているので、もしかしたら正式版とは違うかもしれません。注意です。

とりあえず既存の一つめの方法。%式。式? 演算子?

>>> w = 'world'
>>> 'hello %s' % w
'hello world'

こんなやつ。わりとよく見掛けるやつです。 フォーマット文字列の文法はなんとなくC言語とかのprintfに似てますね。

で、二つめの方法はformatメソッド。

>>> w = 'world'
>>> 'hello {0}'.format(w)
'hello world'

こんなん。ちょっとモダンです。かなり高機能で、色々出来る。 一応これが推奨の方法らしいですが、bytesにも%でフォーマットする方法が導入されたりして、なんだかよくわからない。

そして、新しく導入されるのがf文字列ってやつ。

>>> w = 'world'
>>> f'hello {w}'
'hello world'

シンプルっぽい。 ご覧の通り、というか何というか、変数名をそのまま使えるようになっています。

で、こいつ。formatメソッドと同じような構文で、同じことが出来るように見えます。

>>> n = 12
>>> f'{n:05d}'
'00012'

>>> s = 'hello'
>>> f'{s: <7s}'
'hello'

ゼロ詰めとか、右寄せとか左寄せとか。

なんだー簡単じゃんと思うわけですが、微妙に仕様が違うようです。 どうも、変数名のところに普通のリテラルも書けるようです。 つまりどういうことかというと、普通の計算式を書ける。

>>> f'{12 + 34}'
'46'

>>> n = 1
>>> f'{n * 2}'
'2'

>>> a = 'hello'
>>> b = 'world'
>>> f'{a + " " + b}'
'hello world'

>>> def func(x):
...     return x * 2
... 
>>> f'{func(2)}'
'4'

おお、よくわからなくなってきた。

formatメソッドのときはどうだったかというと、計算しようとするとKeyErrorが出たりします。

>>> '{12 + 34}'.format()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: '12 + 34'

うん、分かりやすい反応

それでも概ね使い方に違いは無さそうですが、とりあえず違いが影響しそうなのはdict型にアクセスするときとか。

>>> d = {'a': 1, 'b': 2}

>>> '{0[a]}'.format(d)
'1'
>>> '{d[b]}'.format(d=d)
'2'
>>> '{0["a"]}'.format(d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: '"a"'

>>> f'{d["a"]}'
'1'
>>> key = 'b'
>>> f'{d[key]}'
'2'
>>> f'{d[a]}'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

こんなん。 普通の値か、それとも専用のミニ言語か、というような感じの違いなんでしょうね、きっと。 考えてみりゃ当然のことですが、ちょっとふしぎ。

文字列の定義と同時にしか使えない(多分)し、使えたとしてもセキュアじゃない感じがするし、既存の方法の置き換えというわけにはいかなそうです。 状況に応じて色々組み合せる必要性がありそう。うーむ。

参考: Pythonの新しい文字列フォーマット : %記号、str.format()から文字列補間へ | プログラミング | POSTD