質問: {'y': 1, 'm': 8} print(f"{d['y']}, {d['m']}") でうまくいきました。 また、f-strings は{}内をexpressionで評価するそうですがstr.format()は{}内をどのように評価するのですか。 pithonの公式サイトには str.format(*args, **kwargs) とありますがこのアスタリスクは可変長位置引数と可変長キーワード引数を取るいうことでしょうか。それとも展開するということでしょうか。 初歩的な質問で恐縮ですが、以上のご教示をお願いします。 ### 補足情報(FW/ツールのバージョンなど) ここにより詳細な情報を記載してください。
回答: (A)`"{0[a]}".format({'a': 1})`ではなく (B)`"{0['a']}".format({'a': 1})`の方が自然 という感覚はよくわかります。では (C)`i = 0; "{0['abc'[i]]}".format({'a': 1, 'b': 2, 'c': 3})` と記述できても(例がイマイチで申し訳ないですが)よさそうに感じませんか?つまり整数を`1`、文字列を`'a'`と表記するルールにするなら「整数や文字列のリテラルにとどまらずそれ以外の型を結果とするような任意の式も記述できるようにしないと中途半端」に感じないでしょうか? 実際にformatにはそこまでの能力はなく添え字には「整数」と「文字列」のリテラル相当が指定できるだけです。それでも一応添え字表記ができることによって `"name={0[name]}, id={0[id]}".format({id: 10, name: 'ksoh'})` と記述でき、こうした方が `d = {id: 10, name: 'ksoh'}; "name={0}, id={1}".format(d['name'], d['id'])` と書くよりは「書式化の結果を把握しやすい」という利点を得ることができますよね? このように多少の制限を付けた上でちょっと便利な記述を許す程度にしておくのがformatの設計者の感覚だったのだろうと思います。例えばですが整数のtupleをキーとしたdictに対して ``` d = {(0, 0): 'a', (0, 1): 'b'} d[0, 0] # => 'a' d[0, 1] # => 'b' "{0[0, 0]}, {0[0, 1]}".format(d) # => 'a, b' ``` なんてできたら少し便利かも知れませんが、そこあたりをやり始めると結局「かなり広いPythonの構文解析をせねばならないのは必至」なので「整数と文字列のリテラルだけで止めておこう」というわけですね。整数と文字列のリテラルしか指定できないなら `"{0[0]}, {1['a']}".format(...)` ではなく、どうせ制限の強い仕様なので `"{0[0]}, {1[a]}".format(...)` でいいや・・・ってことではないでしょうか。 もちろん、(C)のような記述を許し「添え字に任意の式を表記できる」ような仕様にもできますけど、そうするためにはformat関数にPythonの言語パーサーと同等の構文解析能力を組み込まなければならなくなります。またプログラムが起動されたのちに書式文字列をPythonの式の構文に従って解析するという大変「遅くてメモリーの消費もばかにならない実装」になることでしょう。 それはformat関数がやろうとしていることに対して「あまりにオーバースペックで、それこそいびつな仕様である」と設計者が考えたのだろうと想像します。 ただ使う側にとってformat関数の書式指定の仕様はなんとも中途半端な感じがするのは同意します。それゆえPython 3.6で「fomrat関数ではなく、Python言語の構文を拡張しスクリプトをパースする時点で書式を解析するようにしたフォーマット済み文字列リテラルが導入された」のだと思います。(このような言語仕様はPython以外の言語でも通常は言語の構文パーサーがソースファイルを解析する時点で解釈するのが一般的だと思います。) フォーマット済み文字列リテラルなら、使う側にとっても納得できる仕様だし実装的にも問題が少ないものにできていると思います。当初からこの言語仕様があればformat関数の仕様に添え字をリテラル限定で指定できる仕様はできなかったかも知れませんね。