【问题标题】:Why isn't it possible to use backslashes in f-strings?为什么不能在 f 字符串中使用反斜杠?
【发布时间】:2019-01-17 10:42:33
【问题描述】:

在 Python >=3.6 中,可以使用 f 字符串替代 str.format 方法。举个简单的例子,这些是等价的:

'{} {}'.format(2+2, "hey")
f'{2+2} {"hey"}'

忽略format specifiers,我基本上可以将str.format 的位置参数移动到f 字符串中的大括号内。请特别注意,我可以只在此处输入 str 文字,尽管它可能看起来有点笨拙。

但是有一些限制。具体来说,backslashes in any shape or form 不允许在 f 字符串的大括号内:

'{}'.format("new\nline")  # legal
f'{"new\nline"}'          # illegal
f'{"\\"}'                 # illegal

如果它在大括号内,我什至不能使用\ 来拆分长线;

f'{2+\
2}'     # illegal

尽管\ 的这种用法完全允许在普通str 中使用;

'{\
}'.format(2+2)  # legal

在我看来,如果解析器在 f 字符串的大括号内看到 \ 字符,则硬停止被编码到解析器中。为什么要实施此限制?尽管docs 指定了这种行为,但它并不能说明原因。

【问题讨论】:

  • @miradulo 请将其发布为答案。
  • @Bakuriu 我要在大约 30 秒后 AFK,如果您愿意,可以自己发布。
  • 我也认为这违反了“最小惊讶原则”。实际上我很惊讶它不接受“\n”字符。我写 Ruby 代码是为了生活,你可以在 #{}interpolation 中编写各种语法正确的 Ruby 代码

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


【解决方案1】:

你似乎期待

'{}'.format("new\nline")

f'{"new\nline"}'

等价。这不是我所期望的,在 Python 3.6 的预发布版本中,f-strings 中的反斜杠不是如何工作的,其中允许大括号之间的反斜杠。那时,您会收到一个错误,因为

"new
line"

不是有效的 Python 表达式。

正如刚才演示的那样,大括号中的反斜杠令人困惑和模棱两可,它们是banned 以避免混淆:

这样做的目的是禁止像这样的复杂代码:

>>> d = {'a': 4}
>>> f'{d[\'a\']}'
'4'

此外,我将禁止在括号中使用转义符,如下所示:

>>> f'\x7bd["a"]}'
'4'

(其中 chr(0x7b) == "{")。

【讨论】:

  • 大括号中的反斜杠很容易混淆,但是外面的反斜杠也是不允许的,这太糟糕了。这个例子并不令人困惑:f"Make your selection \n A- {textA} \n B- {textB} \n C- {textC}".
  • @Guimute:但接下来的问题是\{\x7b 是否启动替换字段。
  • 是的。可能只允许\n\t\r。令人惊讶的是,我刚刚发现 f"/!\\ caution" 没有引发任何错误并且打印正常。
  • @Guimute 您的非混淆示例是完全合法的(至少在 Python 3.7.8 中):f"Make your selection \n A- {textA} \n B- {textB} \n C- {textC}"。我相信反斜杠只在 inside 大括号内是不允许的。
  • @StevenOxley 是的,我现在对那个例子没有任何问题。不幸的是,我不知道在 2 多年前的原始评论时是否是这种情况。
【解决方案2】:

你不能这样做很烦人:

things = ['Thing one','Thing two','Thing three']
print(f"I have a list of things: \n{'\n'.join(things)}")

但你可以这样做:

things = ['Thing one','Thing two','Thing three']
nl = '\n'
print(f"I have a list of things:\n{nl.join(things)}")

【讨论】:

  • 此外,对于多行 f 字符串,textwrap.dedent 的使用完全被破坏,因为默认情况是使用行继续 `dedent('''\` 开始 dedent。这是完全破碎的 imo,py3 开发人员的这种奇怪的纯粹主义态度只会伤害用户。
【解决方案3】:

对于新行,您可以使用os.linesep 而不是\n。例如:

>>> import os
>>> 
>>> print(f"Numbers:\n{os.linesep.join(map(str, [10, 20, 30]))}")
Numbers:
10
20
30

【讨论】:

  • print 的正确行分隔符在所有平台上是 '\n',但在 Windows 上 os.linesep'\r\n' (ref)。我认为'\n' == chr(10) 是有保证的,所以你可以写chr(10).join(...),虽然感觉很hacky。
猜你喜欢
  • 2021-12-16
  • 2012-06-25
  • 1970-01-01
  • 2019-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多