問題意識
たとえば
greeting = "My name is {name}, inmate number {number:04d}"
のような文字列を考える。greeting.format(name='Shohei', number=17)
のようにすれば、name
あるいはnumber
というプレースホルダに明示的に値を与えることもできるし、通常の文字列の代わりにf-stringにすればスコープからname
やnumber
といった名前を引っ張ってきてくれる。
せっかくなのでconfig fileなんかから引っ張ってきた設定も、この方式でフレキシブルにフォーマットできるようにしたい。
もちろん実際に使うときには
cfg = dict(...)
...
text = greeting.format(**cfg)
のようなかたちで使えば良いけれど、実際にformat()
メソッドを呼ぶ前に、cfg
の中に対応したキーが想定された型で入っているかをチェックしたい。
具体的には、たとえば上のgreeting
の場合、このフォーマット文字列から
-
name
という変数が必要 -
number
という変数が、整数に変換できる型で必要
という情報を引き出したい。
stringモジュールの利用
そこで使うのは、format()
メソッドの内部(関連?)実装であるstring
モジュールになる。
string.Formatter
クラスがフォーマッティングにかかわる諸々の作業を抽象化してくれている。今回の場合、parse
メソッドを使う:
>>> import string
>>>
>>> greeting = "My name is {name}, inmate number {number:04d}, cheers!"
>>>
>>> fmter = string.Formatter()
>>> fmter.parse(greeting)
<formatteriterator object at 0x10125b7e0>
>>> for elem in fmter.parse(greeting)
... print(elem)
...
('My name is ', 'name', '', None)
(', inmate number ', 'number', '04d', None)
(', cheers!', None, None, None)
>>>
parse
メソッドは、4-tupleのイテレータを返す。各tupleは(literal, field, spec, conversion)の形式になっている:
- literal: プレースホルダの前にあるリテラル文字列
- field: プレースホルダに指定された名前
- spec: フォーマット形式
- conversion: (現段階では、どういうときに出てくるかちょっとよくわからなかった)
その他参考
- PEP 3101 意外と知らないことがあった