Определите тройную кавычку f-строки с подстрокой, содержащей символ новой строки, внутри функции без выходных отступов - PullRequest
0 голосов
/ 06 января 2019

Я пытаюсь красиво распечатать 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.indent, textwrap.dedent, str.lstrip, re и т. Д., Но код перестает быть простым и быстрым. Самое близкое, что я придумал, это следующее, но длина неловкая, и я чувствую, что повторяюсь.

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

Ответы [ 2 ]

0 голосов
/ 06 января 2019

Вы можете исправить это с 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)
0 голосов
/ 06 января 2019

Я думаю, вы можете попытаться воспользоваться преимуществом неявной конкатенации строк для решения, которое выглядит красиво:

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)
...