Python3のformatメソッドの中途半端なところ

formatメソッドで辞書の値を表示するには以下のように[]の中にキーの文字列を書く。

>>> d = {'foo': 'a'}
>>> "{0[foo]}".format(d)
'a'

では、キーとなる文字列が変数に格納されている場合どうすれば良いか?以下のように、

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

{}をネストすることはできないので、[]内の{1}がキーの文字列であると認識される。これは以下のように回避できる。

>>> "{0}".format(d[key])
'a'

では次に辞書のキーが以下のように文字列でない場合はどうだろうか?

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

本来、[]内は文字列のキーが認識されるはずであるが、整数の1がキーとして認識されている。ところが、実数の場合は、文字列の方が認識されている。文字列型以外のキーを使用すると挙動が怪しいということが分かる。


結局、Rubyのように文字列の中に式を埋め込む方式であれば、"{d[1]}"や"{d['1'}}"のように曖昧さはなかったと思う。ただし、この方法だと右詰めや0埋めや有効桁数などの整形処理ができないし、{d[1]:10}のような組み合わせたやり方は恐らく構文解釈が複雑なので、今の方式で辞書を使用する場合には注意が必要ということを覚えておくしかない。


ちなみに、属性に関しては以下のように文字列が使われるので問題なさそう。

>>> def foo():pass
...
>>> foo.__dict__ = {1: 'a', '1': 'b'}
>>> "{0.1}".format(foo)
'b'
>>> foo.__dict__ = {1.0: 'a', '1.0': 'b'}
>>> "{0.1.0}".format(foo)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute '1'
>>> foo.__dict__ = {True: 'a', 'True': 'b'}
>>> "{0.True}".format(foo)
'b'
>>> foo.__dict__ = {None: 'a', 'None': 'b'}
>>> "{0.None}".format(foo)
'b'