如何在f-string中使用换行符'\n'来格式化输出?

243

25
获胜者是: {name1} {name2} {name3} (其中,{name1}、{name2}、{name3}代表具体的获胜者名称) - wim
在Python 3.12+上,你的代码可以直接运行。 - user3064538
8个回答

261

Python 3.12+

你可以在 f-strings 中使用反斜杠,并且问题中的现有代码按预期工作。请参阅https://docs.python.org/3.12/whatsnew/3.12.html#pep-701-syntactic-formalization-of-f-strings

Python < 3.12

不行。反斜杠不能出现在花括号 {} 内;这样做会导致 SyntaxError

>>> f'{\}'
SyntaxError: f-string expression part cannot include a backslash

这在 f-strings 的 PEP 中有明确规定:

反斜杠不得出现在 f-strings 的表达式部分中,[...]

一种选项是将 '\n' 分配给一个变量名,然后在 f-string 中使用 .join 方法;也就是说,不使用字面量:

names = ['Adam', 'Bob', 'Cyril']
nl = '\n'
text = f"Winners are:{nl}{nl.join(names)}"
print(text)

结果如下:

Winners are:
Adam
Bob
Cyril

另一种选择是根据 @wim 的指定,使用 chr(10) 来获取返回的 \n,然后在那里连接。 f"获胜者为:\n{chr(10).join(names)}" 当然,另一种方式是预先使用 '\n'.join,然后相应地添加名称:
n = "\n".join(names)
text = f"Winners are:\n{n}"

这导致了相同的输出。
注意:
这是f-strings和str.format之间的小差异之一。在后者中,您始终可以使用标点符号,只要解包一个包含这些键的奇怪字典即可。
>>> "{\\} {*}".format(**{"\\": 'Hello', "*": 'World!'})
"Hello World!"

在前者中,不允许使用标点符号,因为不能使用它们作为标识符。
除此之外:我肯定会选择printformat,就像其他答案所建议的那样作为替代方案。我给出的选项只适用于如果你因某种原因必须使用f-strings。
仅仅因为某个东西是新的,并不意味着你应该尝试用它做所有事情;-)

对我来说没有意义:nl = '\n' text = f"Winners are:{nl}"。请使用:text = f"Winners are:\n" - Timo
@Timo OP 需要在格式字符串中的嵌入表达式中使用 join 函数来连接 \n - Dimitris Fasarakis Hilliard
1
我相信@timo的观点是第一个{nl}是不必要的,因为\n不在f-string的表达式部分内。 text = f“获胜者是:\n”是完全可以的,正是{"\n".join()}部分在f-string中引起了问题。 - Sam
1
你有没有想过为什么f-strings会有这种限制?例如,在JavaScript中,你可以在字符串模板中放置任何表达式,而没有这样的限制。 - Ron Inbar
@RonInbar 在Python中,有另外两种格式化字符串的方式,它们不会有限制,并且在f-strings之前就已经存在了。这两种方式分别是'%s' % ('\n')'{}'.format('\n') - Iuri Guilherme

86

如果你想打印一个带有分隔符的字符串列表,不需要使用 f-strings 或其他格式化方法。只需使用 sep 关键字参数来调用 print() 函数:

names = ['Adam', 'Bob', 'Cyril']
print('Winners are:', *names, sep='\n')

输出:

Winners are:
Adam
Bob
Cyril

话虽如此,在这里使用str.join()/str.format()可能比任何f-string的变通方法更简单和易读:

print('\n'.join(['Winners are:', *names]))
print('Winners are:\n{}'.format('\n'.join(names)))

16
到目前为止最好的答案。我现在经常在print函数中使用星号解包来查看某些对象的内部情况,例如 print(*dir(some_object), sep='\n') 或者 print(*vars(some_object), sep='\n') - Rick
2
如果您不想直接打印列表,例如,如果您将其传递给记录器,该怎么办? - bob
1
@bob:那就直接使用str.join()text = '\n'.join(['Winners are:', *names])。顺便说一句,print()可以用于写入_任何文件_(通过file参数指定,默认为sys.stdout)。 - Eugene Yarmash

28

如其他人所说,您不能在f字符串中使用反斜杠,但是您可以使用os.linesep来避开这个问题(尽管请注意,这不会在所有平台上都是\n,并且除非读写二进制文件,否则不建议使用;参见Rick的评论):

>>> import os
>>> names = ['Adam', 'Bob', 'Cyril']
>>> print(f"Winners are:\n{os.linesep.join(names)}")
Winners are:
Adam
Bob
Cyril 

或者以一种不太可读的方式,但保证是\n,使用chr()函数:

>>> print(f"Winners are:\n{chr(10).join(names)}")
Winners are:
Adam
Bob
Cyril

2
不是我干的,但在编写文本时使用os.linesep并不是一个好主意。 - Rick
1
@RickTeachey 我已经在括号中添加了警告并建议了另一种方法。无论如何,OP正在打印到屏幕上,而不是写入以文本模式打开的文件。 - Chris_Rands
我认为这并不重要。 os.linesep 仅适用于以二进制模式读取或读取和写入。我知道在这种情况下它将起到相同的作用,但这是一个不好的习惯。但再说一遍:我不是投反对票的人。对我来说,警告已经足够了。 :) - Rick
这是我选择的答案。 - undefined

11

其他答案提供了如何将换行符放入f-string字段的想法。然而,我认为对于OP提出的示例(可能或可能不是OP实际使用情况的指示),这些想法实际上都不应该被使用。

使用f-strings的整个重点是增加代码的可读性。你可以使用f-strings无法做到的任何事情,你都可以使用format来完成。仔细考虑一下是否有任何关于这个(如果你能做到的话)更易读的东西:

f"Winners are:\n{'\n'.join(names)}"

对于这个:

newline = '\n'
f"Winners are:\n{newline.join(names)}"

...或者这个:

"Winners are:\n{chr(10).join(names)}"

对比这两者:

"Winners are:\n{}".format('\n'.join(names))

最后一种方式至少与其他方式一样易读,如果不是更加易读。

简言之:仅仅因为你有一把闪亮的新螺丝刀而在需要用螺丝刀时使用锤子是不明智的。代码被阅读的频率比它被编写的频率要高得多。

对于其他用例,是的,chr(10)newline 的想法可能是适当的。但对于给定的情况不是这样。


12
可读性是主观的 :) ... 旧的做法适合有技能的人,在某些情况下可能更易读,但对于新手来说几乎未知,因此对他们来说不可读。对于哲学观点,我感到抱歉。 - malmed
2
@malmed 可读性通常不是主观的。在这种情况下绝对不是。但是没有必要长时间争论。 - Rick
1
@malmed 你说得对,可读性在某种程度上是“主观”的,因为它可以通过先前的经验进行训练。但由于我们的大脑和感官有限,可读性可以从物理上衡量,即扫描相关文本的难易程度、人类大脑正确匹配模式的频率、它如何正确地提示我们的大脑关于其他代码的预测(包括语句/行的开头提示结束将是什么),以及它如何更容易地变得更易读给新手。 - mtraceur
认为一个人的职业生涯都会花费在阅读仅包含最新语法的代码上是非常乐观的想法。 - snakecharmerb
1
在许多情况下,@snakecharmerb是正确的。但在科学Python领域,例如,人们倾向于仅使用最新的语法。技术债务不再是一个问题。但你说得没错。 - Rick

3
print(f'{"blah\n"}')

上述语句将引发SyntaxError错误, 但为了避免错误,您可以将包含 \n 的字符串赋值给变量,并在f-string中使用它。
x = "blah\n"
print(f'{x}')

3

在 Python 3.12+ 上,你可以

>>> names = ['Adam', 'Bob', 'Cyril']
>>> print(f"Winners are:\n{'\n'.join(names)}")
Winners are:
Adam
Bob
Cyril

您还可以在f-string的表达式部分重复使用相同的引号。
>>> print(f"Winners are:\n{"\n".join(names)}")        
Winners are:
Adam
Bob
Cyril

查看详情,请参阅PEP 701

1

如果(仅当!)可读性是最重要的,而速度真的不是一个因素时,f-strings非常有用,即使有更简单的编程方法,也可以使简单的函数自文档化。当使用f-strings时,可读性最大化的方法是:(1)清楚明显地更改参数状态的语句,并且(2)在打印参数时,仔细格式化打印语句,并以视觉方式呈现参数以突出显示:

'''
function to print out an identification header, consisting
of the programmer supplied title, lastname, and firstname:
''' 
FORMAT_DATE = "%m-%d-%y %H:%M:%S"

date_and_time = datetime.now()
name_line = f"* {lastname}, {firstname}"
title_line = f"* {title}"
date_line = f"* {date_and_time.strftime(FORMAT_DATE)}"
print(name_line
    + '\n'
    + title_line
    + '\n'
    + date_line)

输出:

* Lovelace, Ada
* Bernoulli Numbers algorithm implemented in Python
* 10-28-42 20:13:22

1
请记住不要使用这种奇怪的方式,虽然也能起到作用:
names = ['Adam', 'Bob', 'Cyril']
text = f"""{'''
'''.join(names)}"""
print(text)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接