繁体   English   中英

嵌套的 f 弦

[英]Nested f-strings

感谢David Beazley 的推文,我最近发现新的Python 3.6 f 弦也可以嵌套:

>>> price = 478.23
>>> f"{f'${price:0.2f}':*>20s}"
'*************$478.23'

或者:

>>> x = 42
>>> f'''-{f"""*{f"+{f'.{x}.'}+"}*"""}-'''
'-*+.42.+*-'

虽然我很惊讶这是可能的,但我不知道它有多实用,什么时候嵌套 f 弦会有用? 这可以涵盖哪些用例?

注意:PEP 本身并没有提到嵌套 f 字符串,但是有一个特定的测试用例

我不认为允许嵌套的格式化字符串文字(通过嵌套,我认为它的意思是f'{f".."}' )是仔细考虑可能的用例的结果,我更相信它只是允许在以便他们符合他们的规范。

规范声明它们支持括号内的完整 Python表达式*。 它还指出,格式化的字符串文字实际上只是一个在运行时计算的表达式(请参阅此处此处)。 因此,只允许将格式化字符串文字作为另一个格式化字符串文字中的表达式才有意义,禁止它会否定对 Python 表达式的完全支持。

您找不到文档中提到的用例(并且只能在测试套件中找到测试用例)的事实是因为这可能是实现的一个很好的(副作用)效果,而不是它的激励用例。


实际上,有两个例外:不允许空表达式,并且 lambda 表达式必须用显式括号括起来。

我想这是在同一行中传递格式化参数,从而简化f-strings 的使用。

例如:

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

当然,它允许程序员编写绝对不可读的代码,但这不是目的:)

我实际上只是遇到了类似的事情(我认为)并认为我会分享。

我的具体情况是一个很大的脏 sql 语句,我需要有条件地有一些非常不同的值,但一些 fstrings 是相同的(也在其他地方使用)。

这是我的意思的快速示例。 我选择的列是相同的(也用于其他地方的其他查询),但表名取决于组,而不是这样,我可以循环执行。

当我有多个这样的参数时,每次都mycols=mycols在 str2 中包含mycols=mycols感觉有点脏。

我不确定这会起作用,但很高兴它起作用了。 至于它是多么的 pythonic,我不太确定 tbh。

mycols='col_a,col_b'

str1 = "select {mycols} from {mytable} where group='{mygroup}'".format(mycols=mycols,mytable='{mytable}',mygroup='{mygroup}')

group = 'group_b'

if group == 'group_a':
    str2 = str1.format(mytable='tbl1',mygroup=group)
elif group == 'group_b':
    str2 = str1.format(mytable='a_very_different_table_name',mygroup=group)

print(str2)

任何基本用例都是您需要一个字符串来完整描述要放入 f 字符串大括号{}内的对象。 例如,您需要字符串来索引字典。

所以,我最终在一个 ML 项目中使用了它,代码如下:

scores = dict()
scores[f'{task}_accuracy'] = 100. * n_valid / n_total
print(f'{task}_accuracy: {scores[f"{task}_accuracy"]}')

由于编写自己的数据库库,我在做一个宠物项目时陷入了困境。 我发现的一件事是:

>>> x = dict(a = 1, b = 2, d = 3)
>>> z = f"""
    UPDATE TABLE 
        bar 
    SET 
        {", ".join([ f'{k} = ?'     for k in x.keys() ])} """.strip()
>>> z
'UPDATE TABLE 
    bar 
SET 
    a = ?, b = ?, d = ?  '

我也对此感到惊讶,老实说,我不确定我是否会在生产代码中做这样的事情,但我也说过我不会在生产代码中做很多其他的事情。

我用它来格式化货币。 给定的值如下:

a=1.23
b=45.67

使用前导 $ 和小数位对齐来格式化它们。 例如

 $1.23
$45.67

使用单个 f 字符串f"${value:5.2f}"进行格式化,您可以获得:

$ 1.23
$45.67

这有时很好,但并非总是如此。 嵌套的 f 字符串f"${f'${value:.2f}':>6}"给你确切的格式:

 $1.23
$45.67

我发现嵌套在执行三元组时很有用。 你的意见会因可读性而异,但我发现这个单行非常有用。

logger.info(f"No program name in subgroups file. Using {f'{prg_num} {prg_orig_date}' if not prg_name else prg_name}")

因此,我的嵌套测试将是:

  • 价值是否被重用? (用于表达式重用的变量)
  • 表达清楚吗? (不超过复杂性)

在 F-string 中,open-paren 和 close-paren 是保留键字符。 要使用 f-string 构建 json 字符串,您必须对括号字符进行转义。 在您的情况下,只有外部括号。

f"\\{f'${price:0.2f}':*>20s\\}"

嵌套 f 字符串与格式说明符中的评估表达式

这个问题是关于在“外部”f 字符串的某些计算表达式中使用 f 字符串的用例。

这与允许计算的表达式出现f 字符串的格式说明符中的功能不同。 后一个功能非常有用并且与这个问题有些相关,因为(1)它涉及嵌套的花括号,所以这可能是人们查看这篇文章的原因,并且(2)在格式说明符中允许嵌套的 f 字符串,就像它们一样在 f 字符串的其他卷曲表达式中。

F 弦嵌套可以帮助单衬

虽然肯定不是允许嵌套 f 字符串动机,但在您需要或想要“单行”(例如 lambda 表达式、推导式、来自终端的python -c命令)的晦涩情况下,嵌套可能会有所帮助。 例如:

print('\n'.join([f"length of {x/3:g}{'.'*(11 - len(f'{x/3:g}'))}{len(f'{x/3:g}')}" for x in range(10)]))

如果您不需要单行代码,则可以通过先定义一个变量然后在 f 字符串的计算表达式中使用变量名称来替换任何句法嵌套(在很多情况下,如果不是大多数情况下,非嵌套版本)可能更易读且更易于维护;但它确实需要提供变量名称):

for x in range(10):
    to_show = f"{x/3:g}"
    string_length = len(to_show)
    padding = '.' * (11 - string_length)
    print(f"length of {to_show}{padding}{string_length}")

嵌套计算表达式(即在格式说明符中)很有用

与真正的 f 字符串嵌套相比,允许f 字符串的“格式说明符”中计算表达式的相关功能非常有用(正如其他人指出的那样),原因如下:

  1. 格式可以在多个 f 字符串或计算表达式之间共享
  2. 格式化可以包括计算数量,这些数量可能因运行而异

下面是一个使用嵌套计算表达式但使用嵌套 f 字符串的示例:

import random

results = [[i, *[random.random()] * 3] for i in range(10)]
format = "2.2f"

print("category,precision,recall,f1")
for cat, precision, recall, f1 in results:
    print(f"{cat},{precision:{format}},{recall:{format}},{f1:{format}}")

然而,即使这种嵌套的使用也可以用不需要语法嵌套的更灵活(也许更干净)的代码代替:

import random

results = [[i, *[random.random()] * 3] for i in range(10)]
def format(x):
    return f"{x:2.2f}"

print("category,precision,recall,f1")
for cat, precision, recall, f1 in results:
    print(f"{cat},{format(precision)},{format(recall)},{format(f1)}")

以下嵌套的 f-string one-liner 在构造命令参数字符串方面做得很好

cmd_args = f"""{' '.join([f'--{key} {value}' for key, value in kwargs.items()])}"""

其中输入{'a': 10, 'b': 20, 'c': 30, ....}

优雅地转换为--a 10 --b 20 --c 30 ... `

一个何时有用的简单示例,以及一个实现示例:有时格式也是一个变量。

num = 3.1415
fmt = ".2f"
print(f"number is {num:{fmt}}")

如果需要一些花哨的格式,这种嵌套可能很有用。

for n in range(10, 1000, 100):
    print(f"{f'n = {n:<3}':<15}| {f'|{n:>5}**2 = {n**2:<7_}'} |")

你可以将它用于动态主义。 例如,假设您有一个变量设置为某个函数的名称:

func = 'my_func'

然后你可以写:

f"{f'{func}'()}" 

这相当于:

'{}'.format(locals()[func]()) 

或者,等效地:

'{}'.format(my_func())

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM