今さらPython3 (45) - 書式設定

第7章を読み進めてます。

入門 Python 3

%なんちゃら

すでに何回か使ってきたけど、%sとかの話。

>>> '%s' % 42
'42'
>>> '%d' % 42
'42'
>>> '%x' % 42
'2a'
>>> '%o' % 42
'52'

%sのところに%の後ろにあるデータを差し込んで表示するというもの。42を文字列(%s)、10進数(%d)、16進数(%x)、8進数(%o)で表示している。

>>> '%s' % 7.03
'7.03'
>>> '%f' % 7.03
'7.030000'
>>> '%e' % 7.03
'7.030000e+00'
>>> '%g' % 7.03
'7.03'

これらは、最初の%sは文字列で再出。10進float形式(%f)、指数形式(%e)、ケタの大きさによって表示がfloatか指数に変わる形式(%g)を使っている。

>>> '%d%%' % 100
'100%'
>>> '%d%' % 100
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: incomplete format
>>> '%d%%' % 100
'100%'

これを見る限り、%という字を表示するために%%と入れているんだね。

>>> actor = 'Richard Gere'
>>> cat = 'Chester'
>>> weight = 28
>>> "My wife's favorite actor is %s" % actor
"My wife's favorite actor is Richard Gere"
>>> "Our cat %s weighs %s pounds" % (cat, weight)
'Our cat Chester weighs 28 pounds'
>>> 

%sの場所に文字列を挿入するのが決まりで、% に続けて%sの部分に入れる値を書いてやる。ただし、複数ある場合は括弧で囲んでタプルにしなさいてな具合。

>>> n = 42
>>> f = 7.03
>>> s = 'string cheese'
>>> '%d %f %s' % (n, f, s)
'42 7.030000 string cheese'
>>> '%10d %10f %10s' % (n, f, s)
'        42   7.030000 string cheese'
>>> '%-10d %-10f %-10s' % (n, f, s)
'42         7.030000   string cheese'

出力幅を固定したいときは、%の後ろに数字を入れる。基本右詰だけど、左詰にしたいときは負の値を入れる。でも、string cheeseは10文字超えているけど全部出ているし、これだとどっちに寄っているか分からない。

>>> '%-10d %-10f %20s' % (n, f, s)
'42         7.030000          string cheese'
>>> '%-10d %-10f %-20s' % (n, f, s)
'42         7.030000   string cheese       '

文字列の場合も原則右詰は同じということだね。

>>> '%10.4d %10.4f %10.4s' % (n, f, s)
'      0042     7.0300       stri'
>>> '%.4d %.4f %.4s' % (n, f, s)
'0042 7.0300 stri'

ドット(.)の後ろの数字を使って表現するのは、出力幅の上限。ただしfloatの場合は小数点以下の桁数となる。

>>> '%*.*d %*.*f %*.*s' % (10, 4, n, 10, 4, f, 10, 4, s)
'      0042     7.0300       stri'

表示幅などの情報を変数化したいときは*を使う。

新しいフォーマット

古いフォーマットというのは、これまで何となく触ったことあったけど、これからやるのは初めて(意識して)見るスタイル。Python3以降しか使わないなら、むしろこの新しい方を覚えた方が良さそう。

>>> '{} {} {}'.format(n, f, s)
'42 7.03 string cheese'

%なんちゃらよりは直感的に分かりやすいかも。

>>> '{2} {0} {1}'.format(f,s,n)
'42 7.03 string cheese'
>>> '{4} {5} {20}'.format(f,s,n)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: tuple index out of range

{}の中の数字はどういう意味かを考える上での実験。n->f->sの順で出力されているので、format()の中のインデックスを示しているという理解で良さそう。

>>> '{n} {f} {s}'.format(n=42, f=7.03, s='string cheese')
'42 7.03 string cheese'

これの方が分かりやすい。

>>> d = {'n':42, 'f':7.03, 's':'string cheese'}
>>> '{0[n]} {0[f]} {0[s]} {1}'.format(d, 'other')
'42 7.03 string cheese other'

ここは、本の誤植でしょ。解説の説明の通りにするなら、上みたいな書き方をする必要があるはず。format()中に2つの引数があって、最初の3つは0なので、dという辞書のキーを指定している。4つ目(最後)のotherはformat()の中にある2つめの引数なので、インデックス的には1を使っているのでこうなる。このフォーマットなら辞書が入れ子になっていても行けそうな気がする。

>>> '{0:d} {1:f} {2:s}'.format(n, f, s)
'42 7.030000 string cheese'
>>> '{n:d} {f:f} {s:s}'.format(n=43, f=7.04, s='string cheeese')
'43 7.040000 string cheeese'
>>> n
42
>>> f
7.03
>>> s
'string cheese'
>>> 

%d, %f, %sなどの代わりに:d, :f, :sを使いますということは、これまでのオプションも使えるという確認。

>>> '{0:10d} {1:10f} {2:10s}'.format(n, f, s)
'        42   7.030000 string cheese'
>>> '{0:10d} {1:10f} {2:10s}'.format(n, f, s)
'        42   7.030000 string cheese'
>>> '{0:>10d} {1:>10f} {2:>10s}'.format(n, f, s)
'        42   7.030000 string cheese'
>>> '{0:<10d} {1:<10f} {2:<10s}'.format(n, f, s)
'42         7.030000   string cheese'
>>> 

ただし右寄せ左寄せは不等号(<>)を使う事で分かりやすくなったね。

>>> '{0:^10d} {1:^10f} {2:^10s}'.format(n, f, s)
'    42      7.030000  string cheese'

センタリングもあるのね。

>>> '{0:>10.4d} {1:>10.4f} {2:10.4s}'.format(n, f, s)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Precision not allowed in integer format specifier
>>> '{0:>10d} {1:>10.4f} {2:10.4s}'.format(n, f, s)
'        42     7.0300 stri      '

ここは仕様が変わったとは言え、整数値にマスキングするケースって、あまりイメージできないので気にしなくても良さげ。

(つづく)