Python3.6のfリテラル文字列(f-string)が便利なのと怖い面について

2017-11-22(Wed) Python

久々にpythonネタで、今年の2月に気がついてほったらかしにしてた話。

fリテラル/フォーマット済み文字列リテラル/f-stringとは

PEP-484で定義, 承認されてpython3.6に入った新しいリテラル表記です。簡単な例はこちら

>>> name = "f-string"
>>> f"{test} death!"
'f-string death!’

中身はstr.formatをそのまま使えるっぽいですが、変数名を直接かいて呼び出せるのが新しいです。

使い方は公式ドキュメントを見たほうが早いです。

2. 字句解析 — Python 3.6.3 ドキュメント

辞書はどうする?

良く辞書を展開する時があるのでfリテラルでも使えるのか試してみました。 公式ドキュメントを見たところ、ダブルクオーテーションの中でシングルクォーテーションを使えば展開できます。

>>> td1 = {"name":"suzuki", "age":"32"}

>>> f"{td1['name']}. age:{td1['age']}"
'suzuki. age:32’

が、いちいちクオーテーションを二種類使うとかっこ悪いですね。。。辞書の場合はstr.formatを使ったほうが楽かも。引数の展開が使えるので。

>>> "{name}. age:{age}".format(**td1)
'suzuki. age:32'

またfリテラルはネストできるらしいです。しかもsrt.formatと同じくformat_specが使えます。(以下の例はPEP498から引用)

#ref:https://www.python.org/dev/peps/pep-0498/#format-specifiers

>>> width = 10
>>> precision = 4
>>> import decimal
>>> value = decimal.Decimal("12.34567")
>>> f"result: {value:{width}.{precision}}"  # nested fields
'result:      12.35'

srt.formatではこんな感じ? わざわざインデックス的な名前を入れてますが、直接変数名など指定できる方がスッキリ見れると思います。

>>> "result: {0:{1}.{2}}".format(value, width, precision)
'result:      12.35'

辞書の展開はstr.formatが便利でした。その他は多分fリテラルが便利そうです。

fリテラルはlambdaも展開できる

後調べてたところ、こちらの方の記事で演算子がそのまま展開できるらしいことも言及されてました。

python3.6で導入されるf文字列はformatメソッドとは違う - BlankTar

もしやとlambdaもそのまま実行できるかと調べたら、出来るブログ記事も見つけました。

Python 3.6の新機能f-strings(フォーマット文字列リテラル)について - Read -> Blog

>>>f"{(lambda :0)()}"
0'

出来ますね。これ使い所によってはやばい気がしてますがどうなんでしょうか?

みんなのpythonで有名な柴田(twitter:@ats)さんのこのブログエントリーでlambdaで結構色々できることを学んだところで

「逆に凄いわ」って感心するPythonのlambda活用法 | TRIVIAL TECHNOLOGIES 4 @ats のイクメン日記

こんな事も実行できます。(もちろんpythonの実行ユーザーの権限によりますが)

>>> f'{(lambda subprocess:subprocess.run(["ls", "-l", "/var/log/"], stdout=subprocess.PIPE))(__import__("subprocess"))}'

>>> f'{(lambda subprocess:subprocess.run(["users"], stdout=subprocess.PIPE))(__import__("subprocess"))}'

サーバー側でインストール済みのパッケージも上記のlambdaを使った方法を使えば持ってこれるので、実行されるとサーバーの内情が垣間見れてしまうかもしれません。特にスクリプトをrootで実行させてたらやばいのでは?(ってあんまり考えられないと思ってますが)

まとめ

fリテラルは便利な半面使い所を注意したほうが良いと思います。

対話インターフェイスやjupyter notebookなどでは便利に使えるので試すときに使って、ライブラリでは扱わないなどが良いのかな。lambda展開できちゃうのが黒魔法っぽくてやけど以上の痛手を追わないように気をつけたいですね。

自分はREPLかJupyterあたりでしか使わないつもりです。

PEP 498 -- Literal String Interpolation | Python.org