🍲

Python の f 文字列の、やや思いがけない挙動

に公開

これは何?

Python の f 文字列の挙動が、ちょっとおもしろかったので記録しておく。

事例

基本?

Python3.13
f"{1.1:{1}}"
#=> '1.1' ... わかる気がする

f"{1.1:{1.0}} / {1.1:{1.1}} / {1.1:{1.2}}"
#=> '1e+00 / 1e+00 / 1.1' ... よくわからない

数値なのか

Python3.13
f"{1.1:{1.9}} / {1.1:{1.10}} / {1.1:{1.11}}"
#=> '1.1 / 1e+00 / 1.1' ... そうきたか

f"{1.1:{1e1}}"
#=> '     1e+00' ... なるほど

大きな数値

Python3.13
len(f"{1.1:{1e2}}")
#=> 100 ... ですよね

len(f"{1.1:{1e16}}")
#=> ValueError: Invalid format specifier '1e+16' ... 1e16 は "100略0.0" にはならないのでエラー。

len(f"{1.1:{1e13}}")
#=> Python がクラッシュ。メモリが足りなかったのかな。

計算してみる

Python3.13
f"{1.1:{1.1*2}}" #=> '1.1'

f"{1.1:{1.1*3}}"
#=> ValueError: precision too big ... 1.1*3 は 3.3000000000000003 になる

f"{1.1:{1.1*4}}" #=> ' 1.1'

あるいは

Python3.13
len(f"{1.1:{1e2/7}}")
#=> ValueError: precision too big ... 小数点以下が長すぎるかな

len(f"{1.1:{1e8/7}}")
#=> 14285714 ... 14285714.285714285 なら OK らしい

符号

Python3.13
f"{1.1:{'+0.0'}} / {1.1:{'-0.0'}} / {1.1:{'0.0'}}"
#=> '+1e+00 / 1e+00 / 1e+00' ... それはそう

f"{1.1:{+0.0}} / {1.1:{-0.0}} / {1.1:{0.0}}"
#=> '1e+00 / 1e+00 / 1e+00' ... "+" は無視される

感想

昔の PHP で感じた手触り。

あんまり Python は使わないのでよく知らないんだけど、

f{a:{b}} は、b という式の評価結果を文字列化したものを書式として a を出力するということみたい。

b が文字列じゃない場合はエラーにしたほうがいいんじゃないの? と思ったんだけど、 {式} が「式の評価結果を文字列化する」だから仕方ないのかな。

そこに {数値} などと書かなければ良いので、困ることは稀なんだと思う。

Discussion