質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

String

Stringは、ゼロ以上の文字から連続してできた文字の集合を扱うデータ型です。基本的にテキストを表すために使われます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1094閲覧

str.format()の{ }内の評価について

0ipanema0

総合スコア15

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

String

Stringは、ゼロ以上の文字から連続してできた文字の集合を扱うデータ型です。基本的にテキストを表すために使われます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

1グッド

0クリップ

投稿2019/03/14 16:31

前提・実現したいこと

pythonの初心者です。
str.format()の引数に辞書を入れたところ、エラーになってしまいました。

発生している問題・エラーメッセージ

KeyError: "'y'"

該当のソースコード

python

1d = {'y': 1, 'm': 8} 2m = "{0['y']}, {0['m']}".format(d) 3print(m)

試したこと

m = "{0[y]}, {0[m]}".format(d)
を実行し、エラーから脱したのですがなぜkeyに『'』が不要なのかということがわかりません。

f-strings では
d = {'y': 1, 'm': 8}
print(f"{d['y']}, {d['m']}")
でうまくいきました。

また、f-strings は{}内をexpressionで評価するそうですがstr.format()は{}内をどのように評価するのですか。
pithonの公式サイトには
str.format(*args, **kwargs)
とありますがこのアスタリスクは可変長位置引数と可変長キーワード引数を取るいうことでしょうか。それとも展開するということでしょうか。

初歩的な質問で恐縮ですが、以上のご教示をお願いします。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

tachikoma👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

(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に対して

python

1d = {(0, 0): 'a', (0, 1): 'b'} 2d[0, 0] # => 'a' 3d[0, 1] # => 'b' 4"{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関数の仕様に添え字をリテラル限定で指定できる仕様はできなかったかも知れませんね。

投稿2019/03/15 04:59

編集2019/03/15 05:04
KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2019/03/15 05:13

なんか長々と書いてしまいましたが・・・ 当初format(*args,**kwargs)の言語仕様の説明から入って、ぐだぐだ書きすぎてしまい、それを編集し余計な説明を省いてみたところ残った内容は結局hayatakaさんコメントと同じになっちゃいました... orz
0ipanema0

2019/03/15 09:37

ご回答感謝します。
hayataka2049

2019/03/15 09:43

>プログラムが起動されたのちに書式文字列をPythonの式の構文に従って解析するという大変「遅くてメモリーの消費もばかにならない実装」になることでしょう あー、formatメソッドは任意の文字列オブジェクトに対して呼べるので、確かにevalしちゃうといろいろ大変ですね。 f-stringsならリテラルなので、実行時にどうこうなる要素はないのでその分柔軟にできるというのは確かに納得しました。
guest

0

なぜkeyに『'』が不要なのかということがわかりません。

そういう仕様であるから、としか言いようが無いのです。

Python

1>>> dct = {1: 'a', '1': 'b', '"1"': 'c'} 2>>> for k in dct: 3... print(type(k), k) 4... 5<class 'int'> 1 6<class 'str'> 1 7<class 'str'> "1" 8>>> 9>>> '{0[1]}'.format(dct) 10'a' 11>>> '{0["1"]}'.format(dct) 12'c'

以前同じような疑問を抱き、調査したことがあります。
Qiita - str.formatの書式指定文字列の、腑に落ちない点


str.format(*args, **kwargs)

とありますがこのアスタリスクは可変長位置引数と可変長キーワード引数を取るいうことでしょうか。それとも展開するということでしょうか。

前者です。

投稿2019/03/14 16:37

編集2019/03/14 16:43
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0ipanema0

2019/03/14 16:53

str.format()の引数にキーワード引数を指定した場合はkwargs変数に辞書として格納されるという認識でよろしいでしょうか。
hayataka2049

2019/03/14 18:05 編集

使い方としてキーワード引数までしか想定してないのでしょう。数字は名前にならないので納得感があります。 ↑すみません、完全に勘違いしていました。辞書そのものを渡してフォーマットの中で添字アクセスした場合の挙動についてか。確かに違和感ありますね。
hayataka2049

2019/03/14 18:14

勘違いついでに。 https://stackoverflow.com/questions/42514939/what-are-valid-keys-according-to-python-str-format-documentation https://www.python.org/dev/peps/pep-3101/ PEP3101によると、「シンプルな構文にしちゃったから無理よ」という話らしいですね。 The rules for parsing an item key are very simple. If it starts with a digit, then it is treated as a number, otherwise it is used as a string. Because keys are not quote-delimited, it is not possible to specify arbitrary dictionary keys (e.g., the strings "10" or ":-]") from within a format string.
LouiS0616

2019/03/15 07:54

@0ipanema0 さん その認識でよろしいかと。 未知のキーワード引数が kwargs にまとめられるのは **kwargs が用意された関数全体に言える話で、それがどのように活用されるかは関数に依ります。 @hayataka2049 さん リンク先拝見しました。 何と言うか、シンプルにしようとした結果、却って理解しづらくなっている気がしますね。 先のQiitaの記事に反映させていただいてもよろしいでしょうか?
hayataka2049

2019/03/15 08:21 編集

私はリンクを貼っただけなので、Qiitaの記事に反映するのであれば特に言うことはありません。
0ipanema0

2019/03/15 09:35

みなさま、ご回答感謝します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問