67

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

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

或者:

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

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

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

4

13 回答 13

77

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

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

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


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

于 2016-12-19T16:31:29.197 回答
12

我猜这是在同一行中传递格式参数,从而简化f 字符串的使用。

例如:

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

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

于 2016-12-25T13:22:33.650 回答
7

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

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

这是我的意思的快速示例。不管怎样,我选择的列都是相同的(并且也用于其他地方的其他查询),但表名取决于组,而不是这样,我只能在循环中执行。

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

我不确定这会奏效,但很高兴它确实奏效了。至于它是如何 pythonic 的,我不太确定。

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)
于 2018-04-10T07:58:40.413 回答
4

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

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

scores = dict()
scores[f'{task}_accuracy'] = 100. * n_valid / n_total
print(f'{task}_accuracy: {scores[f"{task}_accuracy"]}')
于 2020-08-02T20:52:27.987 回答
3

在一个宠物项目上工作时,我因编写自己的数据库库而陷入困境。我发现的一件事是:

>>> 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 = ?  '

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

于 2018-11-10T05:26:39.643 回答
2

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

num = 3.1415
fmt = ".2f"
print(f"number is {num:{fmt}}")
于 2021-07-22T10:43:27.147 回答
2

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

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

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

  • 价值是否被重用?(用于表达式重用的变量)
  • 表达清楚吗?(不超过复杂度)
于 2020-12-08T19:15:47.550 回答
2

以下嵌套的 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 ... `

于 2021-09-29T11:07:27.270 回答
1

我用它来格式化货币。给定值,例如:

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
于 2022-03-01T03:14:12.247 回答
1

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

这个问题是关于在“外部”f-string 的某些评估表达式中使用 f-string 的用例。

这与允许评估表达式出现在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)}")
于 2021-08-07T18:38:41.820 回答
1

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

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

于 2021-02-11T14:21:03.920 回答
1

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

for n in range(10, 1000, 100):
    print(f"{f'n = {n:<3}':<15}| {f'|{n:>5}**2 = {n**2:<7_}'} |")
于 2021-10-25T23:07:50.230 回答
-3

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

func = 'my_func'

然后你可以写:

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

这相当于:

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

或者,等效地:

'{}'.format(my_func())
于 2016-12-19T03:38:10.703 回答