Como escrever uma string muito longa que esteja em conformidade com o PEP8 e evite o E501

203

Como o PEP8 sugere manter abaixo da regra das 80 colunas para o seu programa python, como posso respeitar isso com cadeias longas?

s = "this is my really, really, really, really, really, really, really long string that I'd like to shorten."

Como eu expandiria isso para a seguinte linha, ou seja,

s = "this is my really, really, really, really, really, really" + 
    "really long string that I'd like to shorten."
Federer
fonte

Respostas:

116

A concatenação implícita pode ser a solução mais limpa:

s = "this is my really, really, really, really, really, really," \
    " really long string that I'd like to shorten."

Editar Na reflexão, concordo que a sugestão de Todd de usar colchetes em vez de continuação de linha é melhor por todas as razões que ele fornece. A única hesitação que tenho é que é relativamente fácil confundir cordas entre colchetes com tuplas.

Michael Dunn
fonte
4
É por isso que me senti como um idiota postando a pergunta. Felicidades.
Federer
8
Isso é a continuação da linha escapando da linha final, não apenas da concatenação implícita, e até muito recentemente explicitamente proibida no PEP8, embora agora exista uma permissão, mas NÃO para cadeias longas. A resposta de Todd abaixo está correta.
Aaron Hall
4
Eu gosto do PEP8, mas isso faz parte do PEP8 que eu não gosto. Eu me sinto como a continuação implícito é mais claro, por causa da possibilidade de confusão com tuplas
monknomo
1
Lembre-se de não adicionar espaços em branco após \
Mrinal Saurabh
e se a linha longa estiver no meio de uma cadeia longa de várias linhas?
Thayne
299

Além disso, como as constantes de string vizinhas são concatenadas automaticamente, você também pode codificar da seguinte forma:

s = ("this is my really, really, really, really, really, really, "  
     "really long string that I'd like to shorten.")

Observe o sinal de mais e eu adicionei a vírgula e o espaço extras que seguem a formatação do seu exemplo.

Pessoalmente, não gosto das barras invertidas, e lembro de ter lido em algum lugar que seu uso é realmente preterido em favor dessa forma, que é mais explícita. Lembre-se de que "Explícito é melhor que implícito".

Considero a barra invertida menos clara e menos útil, porque isso está realmente escapando ao caractere de nova linha. Não é possível colocar um comentário final de linha depois, se for necessário. É possível fazer isso com constantes de string concatenadas:

s = ("this is my really, really, really, really, really, really, " # comments ok
     "really long string that I'd like to shorten.")

Eu usei uma pesquisa no Google de "comprimento da linha python", que retorna o link PEP8 como o primeiro resultado, mas também links para outra boa publicação StackOverflow sobre este tópico: " Por que o Python PEP-8 deve especificar um comprimento máximo de linha de 79 caracteres? "

Outra boa frase de pesquisa seria "continuação de linha python".

Todd
fonte
8
+1: "Pessoalmente, não gosto das barras invertidas, e lembro de ler em algum lugar que seu uso é realmente descontinuado em favor desta forma mais explícita. Lembre-se de" Explícito é melhor do que implícito. ""
Alberto Megía,
13
Para todos que recebem uma tupla e se perguntam o porquê. Não adicione vírgulas ao final das linhas aqui, pois isso resultará em uma tupla, não em uma string. ;)
bugmenot123
7
A adição do caractere + não é mais explícita que o exemplo fornecido? Eu ainda consideraria isso implícito. ou seja, em "str1" + "str2"vez de"str1" "str2"
user1318135 3/17/17
4
Na verdade, eu concordo que o sinal de mais é mais explícito, mas faz uma coisa diferente. Transforma a string em uma expressão a ser avaliada, em vez de especificar uma única constante de string em várias partes. Não tenho certeza, mas acho que isso é feito durante a análise, enquanto a expressão precisa ser executada mais tarde. A diferença de velocidade é provavelmente insignificante, a menos que haja um grande número deles. Mas também esteticamente, prefiro a concatenação automática, uma vez que é um caractere a menos por peça.
Todd
4
Essa sintaxe também mantém a possibilidade de aplicar formatação de seqüência de caracteres como:('this is my really, really, really, really, really long {} ' 'that I'd really, really, really, like to {}').format(var1, var2))
Tim
16

Eu acho que a palavra mais importante na sua pergunta foi "sugere".

Os padrões de codificação são coisas engraçadas. Freqüentemente, as orientações fornecidas fornecem uma base muito boa quando foram escritas (por exemplo, a maioria dos terminais é incapaz de exibir> 80 caracteres em uma linha), mas com o tempo elas se tornam funcionalmente obsoletas, mas ainda são rigidamente respeitadas. Eu acho que o que você precisa fazer aqui é avaliar os méritos relativos de "quebrar" essa sugestão específica contra a legibilidade e a capacidade de manutenção do seu código.

Desculpe, isso não responde diretamente à sua pergunta.

ZombieSheep
fonte
Eu concordo totalmente. Existe uma regra semelhante ao estilo Java que também se tornou obsoleta (IMHO).
Iker Jimenez
Sim, eu concordo, no entanto, tem sido preocupante como eu aceitaria isso neste exemplo em particular. Eu sempre tento manter classes, métodos com <80 caracteres, no entanto, eu diria que uma string como esta não tem outro efeito senão talvez negativo.
Federer
1
Você também precisa avaliar sua preferência pessoal em relação ao padrão de codificação da comunidade. Você deseja que novas pessoas possam entrar e se sentir confortável com a formatação de código desde o primeiro dia.
retracile
1
Sei por mim próprio que tendem a manter o limite de 80 caracteres apenas porque ainda faço a maior parte da minha codificação no IDLE e não gosto da maneira como ele lida com a rolagem horizontal. (Barra de rolagem No)
Tofystedeth
@retracile - sim, você faz. Não estou dizendo "Você deve ignorar a orientação", mas sugerindo que, em alguns casos, a orientação não existe necessariamente para o bem da comunidade. Eu não estava ciente das restrições do IDLE (conforme publicado por Tofystedeth), mas nesse caso há um argumento forte para seguir a convenção.
ZombieSheep
13

Você perdeu um espaço e provavelmente precisa de um caractere de continuação de linha, ou seja. a \.

s = "this is my really, really, really, really, really, really" +  \
    " really long string that I'd like to shorten."

ou até:

s = "this is my really, really, really, really, really, really"  \
    " really long string that I'd like to shorten."

Parens também funcionaria em vez da continuação da linha, mas você corre o risco de alguém pensar que pretendia ter uma tupla e que acabara de esquecer uma vírgula. Tomemos, por exemplo:

s = ("this is my really, really, really, really, really, really"
    " really long string that I'd like to shorten.")

versus:

s = ("this is my really, really, really, really, really, really",
    " really long string that I'd like to shorten.")

Com a digitação dinâmica do Python, o código pode ser executado de qualquer maneira, mas produz resultados incorretos com o que você não pretendia.

retrátil
fonte
2

Barra invertida:

s = "this is my really, really, really, really, really, really" +  \
    "really long string that I'd like to shorten."

ou embrulhe em parênteses:

s = ("this is my really, really, really, really, really, really" + 
    "really long string that I'd like to shorten.")
recursivo
fonte
2
Observe que o plus é necessário. Python concatena literais de strings que se seguem.
bukzor
2

Essas são todas ótimas respostas, mas eu não consegui encontrar um plug-in de editor que me ajudasse a editar seqüências "concatenadas implicitamente". Por isso, escrevi um pacote para facilitar as coisas para mim.

No pip (instale parágrafos) se quem estiver vagando por esse tópico antigo quiser conferir. Formata seqüências de várias linhas da mesma maneira que o html (compacta espaço em branco, duas novas linhas para um novo parágrafo, não se preocupa com espaços entre linhas).

from paragraphs import par


class SuddenDeathError(Exception):
    def __init__(self, cause: str) -> None:
        self.cause = cause

    def __str__(self):
        return par(
            f""" Y - e - e - e - es, Lord love you! Why should she die of
            {self.cause}? She come through diphtheria right enough the year
            before. I saw her with my own eyes. Fairly blue with it, she
            was. They all thought she was dead; but my father he kept ladling
            gin down her throat till she came to so sudden that she bit the bowl
            off the spoon. 

            What call would a woman with that strength in her have to die of
            {self.cause}? What become of her new straw hat that should have
            come to me? Somebody pinched it; and what I say is, them as pinched
            it done her in."""
        )


raise SuddenDeathError("influenza")

torna-se ...

__main__.SuddenDeathError: Y - e - e - e - es, Lord love you! Why should she die of influenza? She come through diphtheria right enough the year before. I saw her with my own eyes. Fairly blue with it, she was. They all thought she was dead; but my father he kept ladling gin down her throat till she came to so sudden that she bit the bowl off the spoon.

What call would a woman with that strength in her have to die of influenza? What become of her new straw hat that should have come to me? Somebody pinched it; and what I say is, them as pinched it done her in.

Tudo se alinha facilmente com o (Vim) 'gq'

Shay
fonte
0

Com um, \você pode expandir as instruções para várias linhas:

s = "this is my really, really, really, really, really, really" + \
"really long string that I'd like to shorten."

Deveria trabalhar.

Ikke
fonte
0

Costumo usar alguns métodos não mencionados aqui para especificar grandes seqüências de caracteres, mas são para cenários muito específicos. YMMV ...

  • Blobs de várias linhas de texto, geralmente com tokens formatados (não exatamente o que você estava perguntando, mas ainda assim útil):

    error_message = '''
    I generally like to see how my helpful, sometimes multi-line error
    messages will look against the left border.
    '''.strip()
  • Aumente a variável peça por peça através do método de interpolação de string que você preferir:

    var = 'This is the start of a very,'
    var = f'{var} very long string which could'
    var = f'{var} contain a ridiculous number'
    var = f'{var} of words.'
  • Leia-o de um arquivo. O PEP-8 não limita o comprimento das strings em um arquivo; apenas as linhas do seu código. :)

  • Use força bruta ou seu editor para dividir a string em linhas managaeble usando novas linhas e remova todas as novas linhas. (Semelhante à primeira técnica que listei):

    foo = '''
    agreatbigstringthatyoudonotwanttohaveanyne
    wlinesinbutforsomereasonyouneedtospecifyit
    verbatimintheactualcodejustlikethis
    '''.replace('\n', '')
Larold
fonte
0

Opções disponíveis:

  • barra invertida :"foo" \ "bar"
  • sinal de adição seguido de barra invertida :"foo" + \ "bar"
  • colchetes :
    • ("foo" "bar")
    • colchetes com sinal de adição :("foo" + "bar")
    • PEP8, E502: a barra invertida é redundante entre colchetes

Evitar

Evite colchetes com vírgula: ("foo", "bar")que define uma tupla.


>>> s = "a" \
... "b"
>>> s
'ab'
>>> type(s)
<class 'str'>
>>> s = "a" + \
... "b"
>>> s
'ab'
>>> type(s)
<class 'str'>
>>> s = ("a"
... "b")
>>> type(s)
<class 'str'>
>>> print(s)
ab
>>> s = ("a",
... "b")
>>> type(s)
<class 'tuple'>
>>> s = ("a" + 
... "b")
>>> type(s)
<class 'str'>
>>> print(s)
ab
>>> 
marcanuy
fonte
0

Se você precisar inserir uma literal de cadeia longa e desejar que o flake8 seja desligado, use-o para fechar as diretivas . Por exemplo, em uma rotina de testes, eu defini algumas entradas CSV falsas. Eu descobri que dividi-lo em mais linhas que tinha linhas seria muito confuso, então decidi adicionar um da # noqa: E501seguinte maneira:

csv_test_content = """"STATION","DATE","SOURCE","LATITUDE","LONGITUDE","ELEVATION","NAME","REPORT_TYPE","CALL_SIGN","QUALITY_CONTROL","WND","CIG","VIS","TMP","DEW","SLP","AA1","AA2","AY1","AY2","GF1","MW1","REM"
"94733099999","2019-01-03T22:00:00","4","-32.5833333","151.1666666","45.0","SINGLETON STP, AS","FM-12","99999","V020","050,1,N,0010,1","22000,1,9,N","025000,1,9,9","+0260,1","+0210,1","99999,9","24,0000,9,1",,"0,1,02,1","0,1,02,1","01,99,1,99,9,99,9,99999,9,99,9,99,9","01,1","SYN05294733 11/75 10502 10260 20210 60004 70100 333 70000="
"94733099999","2019-01-04T04:00:00","4","-32.5833333","151.1666666","45.0","SINGLETON STP, AS","FM-12","99999","V020","090,1,N,0021,1","22000,1,9,N","025000,1,9,9","+0378,1","+0172,1","99999,9","06,0000,9,1",,"0,1,02,1","0,1,02,1","03,99,1,99,9,99,9,99999,9,99,9,99,9","03,1","SYN04294733 11/75 30904 10378 20172 60001 70300="
"94733099999","2019-01-04T22:00:00","4","-32.5833333","151.1666666","45.0","SINGLETON STP, AS","FM-12","99999","V020","290,1,N,0057,1","99999,9,9,N","020000,1,9,9","+0339,1","+0201,1","99999,9","24,0000,9,1",,"0,1,02,1","0,1,02,1",,"02,1","SYN05294733 11970 02911 10339 20201 60004 70200 333 70000="
"94733099999","2019-01-05T22:00:00","4","-32.5833333","151.1666666","45.0","SINGLETON STP, AS","FM-12","99999","V020","200,1,N,0026,1","99999,9,9,N","000100,1,9,9","+0209,1","+0193,1","99999,9","24,0004,3,1",,"1,1,02,1","1,1,02,1","08,99,1,99,9,99,9,99999,9,99,9,99,9","51,1","SYN05294733 11/01 82005 10209 20193 69944 75111 333 70004="
"94733099999","2019-01-08T04:00:00","4","-32.5833333","151.1666666","45.0","SINGLETON STP, AS","FM-12","99999","V020","070,1,N,0026,1","22000,1,9,N","025000,1,9,9","+0344,1","+0213,1","99999,9","06,0000,9,1",,"2,1,02,1","2,1,02,1","04,99,1,99,9,99,9,99999,9,99,9,99,9","02,1","SYN04294733 11/75 40705 10344 20213 60001 70222="
"""  # noqa: E501
gerrit
fonte
-1

Eu usei textwrap.dedent no passado. É um pouco complicado, então eu prefiro continuações de linha agora, mas se você realmente quer o recuo do bloco, acho que isso é ótimo.

Código de exemplo (em que o trim é livrar-se do primeiro '\ n' com uma fatia):

import textwrap as tw
x = """\
       This is a yet another test.
       This is only a test"""
print(tw.dedent(x))

Explicação:

dedent calcula o recuo com base no espaço em branco na primeira linha do texto antes de uma nova linha. Se você quiser ajustá-lo, poderá reimplementá-lo facilmente usando ore módulo.

Esse método tem limitações, pois linhas muito longas ainda podem ser mais longas do que você deseja; nesse caso, outros métodos que concatenam seqüências de caracteres são mais adequados.

MrMas
fonte
1
Em vez de recortar, x[1:]você pode colocar uma barra invertida depois x = """para evitar a primeira nova linha.
Michael Dunn