【问题标题】:Define a triple-quoted f-string with newline-containing substrings inside a function without outputted indents在函数内定义一个三引号 f 字符串,其中包含换行符的子字符串,而不输出缩进
【发布时间】:2019-01-06 05:16:56
【问题描述】:

我正在尝试漂亮地打印一个 HTTP 请求(我在这里模拟过)。

from typing import NamedTuple

class RequestMock(NamedTuple):
    method = 'POST'
    url = 'https://bob.com'
    body = 'body1\nbody2'
    headers = {'a': '1', 'b': '2'}

我有一个功能可以做到这一点:

req = RequestMock()

def print1(req):
    headers = '\n'.join(f'{k}: {v}' for k, v in req.headers.items())
    s = '\n'.join([
        f'{req.method} {req.url}',
        headers,
        req.body
    ])
    print(s)

print1(req)
# POST https://bob.com
# a: 1
# b: 2
# body1
# body2

但是当我为了清晰和易于修改而尝试用f-strings 重写它时,我得到了一些不好的缩进:

# what I want the code to look like
def print2(req):
    headers = '\n'.join(f'{k}: {v}' for k, v in req.headers.items())
    s = f"""
    {req.method} {req.url}
    {headers}
    {req.body}
    """
    print(s)

print2(req)
#     POST https://bob.com
#     a: 1
# b: 2
#     body1
# body2

我知道这是因为我使用换行符定义字符串并将它们放在三引号字符串中。有没有一种简单的方法可以使用在函数中定义的三引号 f-string 来获取我正在查看的输出,而不必知道其定义的缩进级别?我玩过textwrap.indenttextwrap.dedentstr.lstripre 等,但代码不再简单和 Pythonic 快。我想出的最接近的是以下内容,但长度很尴尬,我觉得我在重复自己。

def print3(req):
    headers = '\n'.join(f'{k}: {v}' for k, v in req.headers.items())
    s = textwrap.dedent("""
    {method} {url}
    {headers}
    {body}
    """).strip()
    s = s.format(
        method=req.method,
        url=req.url,
        headers=headers,
        body=req.body,
    )
    print(s)
print3(req)
# POST https://bob.com
# a: 1
# b: 2
# body1
# body2

【问题讨论】:

  • 注意:我试图让this 更具可读性
  • 您可以在print() 的括号内将普通的python 字符串链接在一起。这样,您只需按 Enter 即可添加更多内容。
  • @GeeTransit 我真正感兴趣的是 formatting 字符串的更一般的概念。然后我可以随意通过他们。
  • '\n'.join(line.lstrip() for line in f'''insert \n multiline \n string \n here \n {variable}'''.split('\n'))
  • 在评论中看起来很奇怪...它使用三重引号f-strings,因此您只需在前面添加部分,离开中间,然后添加结尾.split('\n')

标签: python formatting f-string


【解决方案1】:

我认为您可以尝试利用隐式字符串连接来获得一个看起来不错的解决方案:

def print4(req):
    headers = '\n'.join(f'{k}: {v}' for k, v in req.headers.items())
    s = (f'{req.method} {req.url}\n'
         f'{headers}\n'
         f'{req.body}')
    print(s)

print4(req)

输出:

POST https://bob.com
a: 1
b: 2
body1
body2

请注意,如果需要,您可以去掉括号并使用反斜杠:

s = f'{req.method} {req.url}\n' \
    f'{headers}\n'              \
    f'{req.body}'

但是,样式指南更喜欢括号而不是反斜杠。


另一种选择:

def print5(req):
    headers = '\n'.join(f'{k}: {v}' for k, v in req.headers.items())
    s = f"""
    {req.method} {req.url}
    {headers}
    {req.body}
    """
    s = '\n'.join(l.lstrip() for l in s.splitlines())
    print(s)

【讨论】:

  • 试试标准库中的s = textwrap.dedent(s),而不是s = '\n'.join(l.lstrip() for l in s.splitlines())
【解决方案2】:

您可以通过 2 个微小的更改来修复它:

def print6(req, **w):
    headers = '\n'.join(f'{k}: {v}' for k, v in req.headers.items())
    method, url, body = \
        w['method'], w['url'], w['body']
    #   < note the changes belowwwwwwwwwwww >
    s = '\n'.join(line.lstrip() for line in f"""
    {method} {url}
    {headers}
    {body}
    """.split('\n')) # and note this .split('\n') over here
    print(s)
print6(req)

【讨论】:

  • 这打印{method} {url}\n{headers}\n{body}
  • 哎呀...忘记了三引号之前的f。哈。
  • NameError: name 'method' is not defined 应该是req.methodreq.url等等。
  • 可以在函数外定义。我可以更改它,以便它可以从其中获取名称。编辑:Nvm,我再次检查了他的问题。我需要更加专注:D
猜你喜欢
  • 1970-01-01
  • 2014-05-29
  • 1970-01-01
  • 1970-01-01
  • 2014-10-15
  • 2022-01-15
  • 1970-01-01
  • 2017-03-16
  • 1970-01-01
相关资源
最近更新 更多