【问题标题】:Nested f-strings嵌套的 f 字符串
【发布时间】:2017-05-04 01:52:49
【问题描述】:

感谢David Beazley's tweet,最近发现新的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 字符串,但是有一个 specific test case

【问题讨论】:

  • 可能与嵌套旧 str.format:stackoverflow.com/questions/40245650/… 的目的完全相同
  • 又一个不错的here。我将把是否欺骗锤子的决定权交给你。
  • @TigerhawkT3 感谢您提供的好例子!我不确定这些是直接重复的,但肯定是相关的——就关闭而言……我会接受社区的任何决定。我也希望这里可能有一些特定于 f-strings 的东西。我们或许应该给话题时间和机会。
  • 不确定是否值得回答,但金字塔现在更容易在一行中打印print("\n".join(f'{a:{a}<{a}}' for a in range(1,10)))
  • 我刚才为计时器做了这个怪物:f'''A timer has been set for {f"{hrs:02d}:{mins:02d}:{secs:02d}" if hrs > 0 else f"{f'{mins:02d}:{secs:02d}' if mins > 0 else f'{secs} seconds'}"}!'''

标签: python python-3.x string-formatting python-3.6 f-string


【解决方案1】:

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

func = 'my_func'

那么你可以写:

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

相当于:

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

或者,等效地:

'{}'.format(my_func())

【讨论】:

  • 我试过了,没用。 TypeError: 'str' object is not callable
  • 这不是真的。 f'{func}' 是一个字符串。你不能调用字符串。
  • 如果您遇到此类不安全的黑客攻击,您可能正在寻找eval
【解决方案2】:

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

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

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


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

【讨论】:

  • 恐怕你是对的,完全同意。今天没有赞成票 - 明天会回来。谢谢。
  • @alecxe 我很确定一些涉及f-string 嵌套的古怪事情会在某个时候在野外弹出:-)
  • 是的,刚刚遇到了一个我需要嵌套 f"…" 的案例,并使用它来让我自己高兴?另一个 Python 完全是 schnufte 的原因!
  • 我不能将字符串放在 f-strings 中的引号中,更不用说其他 f-strings。
【解决方案3】:

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

例如:

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

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

【讨论】:

  • 是的! str.format 一直支持这一点,例如 '{0:.{1}f}'.format(math.pi, 4)'3.1416'。如果 f-string 不能支持,那就太糟糕了。
  • 您的示例没有显示嵌套的 f 字符串,只是嵌套的花括号。
【解决方案4】:

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

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

这是我的意思的快速示例。我选择的 cols 无论如何都是相同的(并且也用于其他地方的其他查询),但表名取决于组并且不是这样我可以在循环中执行它。

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

我不确定这会奏效,但很高兴它确实奏效了。至于它是如何 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)

【讨论】:

  • 您可以在字符串文字中使用{{my_table}},而不是用{my_table} 替换第3 行的my_table 中的my_tableformat 然后将双括号转换为单括号。所以你会有更短的代码:str1 = "select {mycols} from {{mytable}} where group='{{mygroup}}'".format(mycols=mycols)
【解决方案5】:

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

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

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

【讨论】:

  • “我写自己的数据库库让我走神了”哈哈哈 :) 是的,这很有趣,不,我也永远不会在生产中使用它:)
  • @ChristopherMahan 我几年前退休了,所以有时我有时间探索一些不好的想法。如果你很好奇 github.com/devdave/dcdb 缺少一长串功能,但没关系,因为我有时间实现它们或快速返回 sqlalchemy。
【解决方案6】:

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

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

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

【讨论】:

    【解决方案7】:

    我发现嵌套在做三元组时很有用。您对可读性的看法会有所不同,但我发现这种单行代码非常有用。

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

    因此,我的嵌套测试是:

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

    【讨论】:

      【解决方案8】:

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

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

      【讨论】:

        【解决方案9】:

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

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

        【讨论】:

          【解决方案10】:

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

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

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

          F-string 嵌套有助于单行

          虽然肯定不是 允许嵌套 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 字符串的评估表达式中使用变量名称来替换任何语法嵌套(在许多情况下,如果不是大多数情况下,非-nested 版本可能更易读且更易于维护;但它确实需要提供变量名):

          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)}")
          

          【讨论】:

            【解决方案11】:

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

            【讨论】:

              【解决方案12】:

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2021-04-23
                • 2021-02-01
                • 1970-01-01
                • 1970-01-01
                • 2022-11-21
                • 2016-02-08
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多