kb84tkhrのブログ

何を書こうか考え中です あ、あと組織とは関係ないってやつです 個人的なやつ

Formatted string literals (続き)

ここをもう少し見てみる

f_expression      ::=  (conditional_expression | "*" or_expr)
                         ("," conditional_expression | "," "*" or_expr)* [","]
                       | yield_expression

6. Expressions — Python 3.7.3 documentation は上のほうが葉に近い要素の定義で、ボトムアップな順で定義されているようだ

conditional_expression ::=  or_test ["if" or_test "else" expression]
expression             ::=  conditional_expression | lambda_expr

conditional_expressionはif式で、それにlambda式を加えた
expressionが一般の式になるということだろう

逆に見ると、formatted stringの{}内に書ける式(f_expression)は
lambda式以外の一般の式に加え、* or_exprやyield式を書けるということ
(yield式は一般の式に含まれてないのか)

* or_exprってなんだろう
or_exprっていうのはざっくりいうと比較演算が入らない式
アンパッキングみたいなものかと思ったけど違うみたい

>>> l = [1, 2, 3]
>>> f"{l}"
'[1, 2, 3]'
>>> a, *b = l
>>> a
1
>>> b
[2, 3]
>>> f"{*l}"
  File "<stdin>", line 1
SyntaxError: can't use starred expression here

f"{*l}"でも構文的にはあってると思うんだけど
アンパッキングは左辺だしここでは右辺値だから違うんだよな
右辺値にアスタリスクが出てきたら何だっけ
関数の引数リストで引数にアスタリスクをつけると可変長引数だったりするけど
使い方がわからない

普通のアンパッキング用の定義(らしきもの)は別の個所で出てくる
形は似ている

expression_list    ::=  expression ("," expression)* [","]
starred_list       ::=  starred_item ("," starred_item)* [","]
starred_expression ::=  expression | (starred_item ",")* [starred_item]
starred_item       ::=  expression | "*" or_expr

何かほかを探す
__format__()を調べる?
str.formatの{}には式は書けないから参考にならなさそう
PEP 498 – Literal String Interpolationもざっと見てみたけどそれっぽい説明がないなあ
PEP 502 – String Interpolation - Extended Discussionもな
わからん!

勢いあまってStackoverflowデビューした

python - What does a star (asterisk) do in f-string? - Stack Overflow

けっこうな勢いで反応があって驚いている
が、こうやって使うんだよという人は現れない
ドキュメントのミスか、あるいは将来の予約ってことかね
将来の予約ならPEPに書いてあってもよさそうなもの

ところでlambdaの扱いについて
f_expressionにはlambda_exprは含まれないみたいな定義だけど
lambdaが書けるっていう記事も出てくる
どういうことか

lambda_exprの定義はこう

lambda_expr        ::=  "lambda" [parameter_list] ":" expression

ああ
つまりこうは書けないけど

>>> f"{lambda x: x + 1}"
  File "<fstring>", line 1
    (lambda x)
             ^
SyntaxError: unexpected EOF while parsing

これなら書けるってことね

>>> f"{(lambda x: x + 1)(2)}"
'3'

こっちはlambda_exprと見せかけてcallだから、ってことでいいかな

call                 ::=  primary "(" [argument_list [","] | comprehension] ")"

同じ意味でもこれなら書ける

>>> def add1(x): return x + 1
...
>>> f"{add1}"
'<function add1 at 0x019EF810>'

これと同じ結果になってもいいわけだけど
できなくても別に困ることはなさそう

(ってPEPに書いてあったことを後になって発見)