PEP 3101:高度な文字列書式指定
Python 3.0では、Microsoftの.NET複合書式指定機能に基づいた、新しい強力な文字列書式指定が導入されました。.NET複合書式指定機能を選んだのは慧眼です。これまでさまざまなプログラミング言語の文字列書式指定機能を利用してみて、.NET複合書式指定を採用しているC#の書式指定が1番よかったと感じています。高機能で、柔軟性と一貫性があり、ドキュメントも分かりやすいものになっています。
ところで、PEP-3101にある.NET複合書式指定へのリンクは正しくありません(執筆時点)。正しいURLはhttp://msdn.microsoft.com/en-us/library/txafckwd.aspx、日本語版リンクはhttp://msdn.microsoft.com/ja-jp/library/txafckwd.aspxです。
Python 2.xでは、文字列書式指定に%
演算子またはstring.Template
を使用していました。%
演算子は便利で、引数1つだけを書式指定するときはそのまま渡すことができます。
import time >>> time.localtime() (2008, 12, 31, 10, 32, 16, 2, 366, 0) >>> 'The current year is %d' % time.localtime()[0] 'The current year is 2008'
複数の引数を書式指定するには、それらをタプルまたはリストにまとめる必要があります。
>>> t = time.localtime() >>> 'Day: %d, Month: %d, Year: %d' % (t[2], t[1], t[0]) 'Day: 31, Month: 12, Year: 2008'
タプルまたはリストを使用する場合、書式指定する順番どおりに引数を指定する必要があります。また、同じ値を複数回表示させるには、複数回書式指定する必要があります。
>>> s = 'The solution to the square of %d is: %d * %d = %d' >>> s % (5, 5, 5, 5 * 5) 'The solution to the square of 5 is: 5 * 5 = 25'
または、ディクショナリを渡して、書式指定文字列内でディクショナリキーを指定する方法もあります。
>>> d = dict(n=5, result=5 * 5) >>> s = 'The solution to the square of %(n)d is: %(n)d * %(n)d = %(result)d' >>> s % d 'The solution to the square of 5 is: 5 * 5 = 25'
このように、ディクショナリを使用する場合には、繰り返される値を1度指定するだけで済みますが、それには高い代償もあり、書式指定文字列より複雑になる上、値をただ渡す代わりにdict
を準備する必要も生じます。
最後に、string.Template
クラスを使用する方法があります。これを使用してコンパイル済みのテンプレートを用意すると、異なる値に何回も適用でき、書式指定文字列自体は1回しか解析されないので、効率的です。このことは、テンプレート化されているWebページやコード生成シナリオなど、テスト結果が大きくなったり、書式指定文字列解析の負荷が高くなったりしやすい状況で特に重要になります。書式指定文字列は若干異なります。名前付き値は、先頭に$
記号を付け、必要に応じて前後のテキストから区別するために中かっこで囲みます。
>>> s = 'The solution to the square of ${n} is: ${n} * ${n} = ${result}' >>> t = string.Template(s) >>> for i in range(1, 7): ... d = dict(n=i, result=i * i) ... print t.substitute(d) ... The solution to the square of 1 is: 1 * 1 = 1 The solution to the square of 2 is: 2 * 2 = 4 The solution to the square of 3 is: 3 * 3 = 9 The solution to the square of 4 is: 4 * 4 = 16 The solution to the square of 5 is: 5 * 5 = 25 The solution to the square of 6 is: 6 * 6 = 36
Python 3.0では、string
クラスにformat()
という新しい書式指定メソッドが追加されました。これは、短い書式指定文字列用に%
書式指定に代わるものとして導入されました。書式指定文字列のコンパイルは行わないので、string.Template
書式指定の代わりにはなりません。format()
メソッドは、1つの書式指定文字列内で位置指定引数とキーワード引数の両方を認識します。書式指定文字列内の置き換えフィールドは中かっこで囲みます。同じ位置指定引数を異なるフィールドで複数回再使用できます。
>>> s = 'Addition is commutative. For example: {0} + {1} = {1} + {0}' >>> s.format(5, 7) 'Addition is commutative. For example: 5 + 7 = 7 + 5' >>> s.format(4, 3, result=3 * 4) '4 multiplied by 3 is 12'
中かっこ自体は中かっこ2つで表します。
>>> '{0} "{{", {1} "}}"'.format('open curly:', 'closed curly:') 'open curly: "{", closed curly: "}"'
format()
メソッドでは、文字列や10進整数などの単純なフィールドと、複合フィールドの両方がサポートされます。複合フィールドは、オブジェクト属性や配列要素を使用できるのでとても便利です。
>>> import fractions >>> r = fractions.Fraction(5, 4) >>> '{0.numerator} / {0.denominator}'.format(r) '5 / 4' >>> 'Day: {0[2]}, Month: {0[1]}, Year: {0[0]}'.format(time.localtime()) 'Day: 31, Month: 12, Year: 2008'
属性や配列要素を使用できると、オブジェクト、タプル、リスト、配列をそのまま指定でき、各部に分解して正しい順番に並べ直す必要がないので、作業が単純になります。前に示したPython 2.xバージョンの例と、上記の例を比べてみてください。
一部のテンプレート言語とは異なり、書式指定文字列には任意のPython表現は使用できません。Python 3.0書式指定文字列は、オブジェクト、属性、およびタプル/配列/リストのインデックスに限定されます。
format()
メソッドでは、書式指定されたフィールドの表示を細かく制御する広範な書式指定子を使用できます。書式指定子とフィールド名はコロン(:
)で区切ります。
'The "{0:10}" is right padded to 10 characters'.format('field') 'The "field " is right-padded to 10 characters'
オブジェクトの__format__
メソッドに独自の書式指定子を定義、指定できますが(後述の例を参照)、すべてのオブジェクトに適用できる標準指定子も、Pythonで多数用意されています。標準書式指定子の汎用形式は次のようになっています。
[[fill]align][sign][#][0] [minimumwidth][.precision][type]
多数の細かいルールや制約があります。書式指定子によっては、数値型にしか対応しないものや、別の指定子もないと機能しないものもあります。整数と実数には、次のようにさまざまな表示オプションがあります。
>>> '{0:@^8.4}'.format(1 / 3) '@0.3333@'
さて、これはどうなっているのでしょうか。アットマーク(@
)は埋め込み文字です。配置として中央揃え(^
)が指定され、有効桁数が4、最小幅が8に指定されています。その結果、数値は有効桁数4桁で表され(0.3333)、ゼロと小数点の分、2文字増え、さらに埋め込み文字@
が2つ追加されて、合計8文字が中央揃えで表示されます。いずれもPython 2.xの%
書式指定より簡潔で、しかもより柔軟性があり高機能です。
新しい文字列書式指定機能の真の力は、__format__()
メソッドを実装して定義するカスタム書式指定で発揮されます。このメソッドのシグネチャは次のとおりです。
def __format__(self, format_spec): ...
さまざまな色による表示を書式指定できるColorString
というクラスを作成するとします。Pythonで、色指定されたテキストなどを画面に出力するには、LinuxとMac OS XではANSIエスケープコードを、32ビットWindowsではSetConsoleTextAttribute()
APIを使用できます。
ここに示すコードは、Windowsでは適切に表示されません。色が変わる代わりに、元のテキストの前後に不要な文字が出力されます。
従って、テキストを赤い色で出力するには、次のようにします。
print('\033[31mRed Text\033[0m')