Cómo escribir cadenas muy largas que se ajusten a PEP8 y eviten E501

203

Como PEP8 sugiere mantener debajo de la regla de 80 columnas para su programa de Python, ¿cómo puedo cumplir con las cadenas largas?

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

¿Cómo haría para expandir esto a la siguiente línea, es decir

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

Respuestas:

116

La concatenación implícita podría ser la solución más limpia:

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

Editar Reflexionando Estoy de acuerdo en que la sugerencia de Todd de usar corchetes en lugar de la continuación de línea es mejor por todas las razones que da. La única duda que tengo es que es relativamente fácil confundir cadenas entre corchetes con tuplas.

Michael Dunn
fuente
44
Es por eso que me sentí como un idiota publicando la pregunta. Salud.
Federer
8
Esta es la continuación de la línea al escapar de la línea final, no simplemente concatenación implícita, y hasta hace muy poco tiempo explícitamente prohibido en PEP8, aunque ahora hay una asignación, pero NO para cadenas largas. La respuesta de Todd a continuación es correcta.
Aaron Hall
44
Me gusta PEP8, pero esto es parte de PEP8 que no me gusta. Siento que la continuación implícita es más clara, debido a la posibilidad de confusión con las tuplas
monknomo
1
Recuerde no agregar espacios en blanco después de \
Mrinal Saurabh
¿Qué pasa si la línea larga está en el medio de una cadena larga de varias líneas?
Thayne
299

Además, debido a que las constantes de cadena vecinas se concatenan automáticamente, también puede codificarlo así:

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

Tenga en cuenta que no hay signo más, y agregué la coma extra y el espacio que sigue al formato de su ejemplo.

Personalmente, no me gustan las barras invertidas, y recuerdo haber leído en alguna parte que su uso en realidad está en desuso a favor de este formulario, que es más explícito. Recuerde que "explícito es mejor que implícito".

Considero que la barra invertida es menos clara y menos útil porque en realidad se está escapando del carácter de nueva línea. No es posible poner un comentario de final de línea después de él si fuera necesario. Es posible hacer esto con constantes de cadena concatenadas:

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

Utilicé una búsqueda en Google de "longitud de línea de python" que devuelve el enlace PEP8 como primer resultado, pero también enlaces a otra buena publicación de StackOverflow sobre este tema: " ¿Por qué Python PEP-8 debe especificar una longitud de línea máxima de 79 caracteres? "

Otra buena frase de búsqueda sería "continuación de línea de python".

Todd
fuente
8
+1: "Personalmente no me gustan las barras diagonales inversas, y recuerdo haber leído en alguna parte que su uso en realidad está en desuso a favor de esta forma que es más explícita. Recuerde" explícito es mejor que implícito ""
Alberto Megía
13
Para todos los que obtienen una tupla y se preguntan por qué. No agregue comas al final de las líneas aquí, eso dará como resultado una tupla, no una cadena. ;)
bugmenot123
77
¿Agregar el carácter + no es más explícito que el ejemplo dado? Todavía lo consideraría implícito. es decir, en "str1" + "str2"lugar de"str1" "str2"
user1318135
44
De hecho, estoy de acuerdo en que el signo más es más explícito, pero hace algo diferente. Convierte la cadena en una expresión para evaluar, en lugar de especificar una sola cadena constante en varias piezas. No estoy seguro, pero creo que esto se hace durante el análisis, mientras que la expresión debe ejecutarse más tarde. La diferencia de velocidad es probablemente insignificante a menos que haya una gran cantidad de ellos. Pero también estéticamente prefiero la concatenación automática ya que es un carácter menos desordenado por línea.
Todd
44
Esta sintaxis también mantiene la posibilidad de aplicar formato de cadena como:('this is my really, really, really, really, really long {} ' 'that I'd really, really, really, like to {}').format(var1, var2))
Tim
16

Creo que la palabra más importante en su pregunta fue "sugiere".

Los estándares de codificación son cosas divertidas. A menudo, la guía que proporcionan tiene una base realmente buena cuando se escribió (por ejemplo, la mayoría de los terminales no pueden mostrar> 80 caracteres en una línea), pero con el tiempo se vuelven funcionalmente obsoletos, pero aún se adhieren rígidamente. Supongo que lo que debe hacer aquí es sopesar los méritos relativos de "romper" esa sugerencia particular frente a la legibilidad y mantenibilidad de su código.

Lo sentimos, esto no responde directamente a su pregunta.

ZombiOvejas
fuente
Estoy totalmente de acuerdo. Hay una regla de estilo Java similar que también se ha vuelto obsoleta (en mi humilde opinión).
Iker Jimenez
Sí, estoy de acuerdo, sin embargo, me ha estado atormentando cómo lo cumpliría en este ejemplo en particular. Siempre trato de mantener clases, métodos para <80 caracteres, sin embargo, diría que una cadena como esta no tiene otro efecto que quizás sea negativo.
Federer
1
También debe sopesar su preferencia personal con el estándar de codificación de toda la comunidad. Desea que nuevas personas puedan entrar y sentirse cómodas con el formato del código desde el primer día.
retroceder
1
Lo sé por mi propia cuenta, tiendo a mantener el límite de 80 caracteres solo porque todavía hago la mayor parte de mi codificación en IDLE y no me gusta la forma en que maneja el desplazamiento horizontal. (Sin barra de desplazamiento)
Tofystedeth
@retracile: sí, lo haces. No estoy diciendo "Debes ignorar la guía", más bien sugiero que en algunos casos la guía no necesariamente está ahí para el bien de la comunidad. No estaba al tanto de las restricciones de IDLE (según lo publicado por Tofystedeth) pero en ese caso hay un argumento contundente para seguir la convención.
ZombieSheep
13

Perdió un espacio y probablemente necesite un carácter de continuación de línea, es decir. a \.

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

o incluso:

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

Parens también funcionaría en lugar de la continuación de la línea, pero se arriesga a que alguien piense que tiene la intención de tener una tupla y acaba de olvidar una coma. Toma por ejemplo:

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

Con la escritura dinámica de Python, el código puede ejecutarse de cualquier manera, pero produce resultados incorrectos con el que no tenía la intención.

retroceder
fuente
2

Barra invertida:

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

o envolver en parens:

s = ("this is my really, really, really, really, really, really" + 
    "really long string that I'd like to shorten.")
recursivo
fuente
2
Tenga en cuenta que la ventaja es necesaria. Python concatena literales de cadena que se suceden.
bukzor
2

Estas son todas excelentes respuestas, pero no pude encontrar un complemento de editor que me ayudara a editar cadenas "concatenadas implícitamente", así que escribí un paquete para que me sea más fácil.

En pip (instale los párrafos) si quienquiera que esté vagando por este viejo hilo le gustaría verlo. Formatea cadenas de varias líneas como lo hace html (comprime espacios en blanco, dos líneas nuevas para un nuevo párrafo, no te preocupes por los espacios entre líneas).

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

se convierte en ...

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

Todo se alinea fácilmente con (Vim) 'gq'

Shay
fuente
0

Con un \puede expandir declaraciones a varias líneas:

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

Deberia trabajar.

Ikke
fuente
0

Tiendo a usar un par de métodos no mencionados aquí para especificar cadenas grandes, pero estos son para escenarios muy específicos. YMMV ...

  • Bloques de texto de varias líneas, a menudo con tokens formateados (no exactamente lo que estaba preguntando, pero aún útil):

    error_message = '''
    I generally like to see how my helpful, sometimes multi-line error
    messages will look against the left border.
    '''.strip()
  • Haga crecer la variable pieza por pieza a través del método de interpolación de cadenas que prefiera:

    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.'
  • Léelo de un archivo. PEP-8 no limita la longitud de las cadenas en un archivo; solo las líneas de tu código. :)

  • Use la fuerza bruta o su editor para dividir la cadena en líneas manejables usando líneas nuevas y luego elimine todas las líneas nuevas. (Similar a la primera técnica que enumeré):

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

Opciones Disponibles:

  • barra invertida :"foo" \ "bar"
  • signo más seguido de barra invertida :"foo" + \ "bar"
  • soportes :
    • ("foo" "bar")
    • soportes con signo más :("foo" + "bar")
    • PEP8, E502: la barra diagonal inversa es redundante entre paréntesis

Evitar

Evite los corchetes con coma: ("foo", "bar")que define una 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
fuente
0

Si debe insertar un literal de cadena larga y desea que flake8 se cierre, puede usar sus directivas de cierre . Por ejemplo, en una rutina de prueba definí alguna entrada falsa de CSV. Descubrí que dividirlo en más líneas que tenía filas sería muy confuso, así que decidí agregar un de la # noqa: E501siguiente manera:

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
fuente
-1

He usado textwrap.dedent en el pasado. Es un poco engorroso, así que prefiero continuar con las líneas ahora, pero si realmente quieres la sangría de bloque, creo que es genial.

Código de ejemplo (donde el recorte es deshacerse del primer '\ n' con un corte):

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

Explicación:

dedent calcula la sangría en función del espacio en blanco en la primera línea de texto antes de una nueva línea. Si desea modificarlo, puede volver a implementarlo fácilmente utilizando el remódulo.

Este método tiene limitaciones porque las líneas muy largas pueden ser más largas de lo que desea, en cuyo caso otros métodos que concatenan cadenas son más adecuados.

MrMas
fuente
1
En lugar de recortar x[1:], puede colocar una barra invertida después x = """para evitar la primera línea nueva.
Michael Dunn