Come scrivere una stringa molto lunga conforme a PEP8 e prevenire E501


203

Come PEP8 suggerisce di mantenere al di sotto della regola delle 80 colonne per il tuo programma Python, come posso attenermi a questo con stringhe lunghe, ad es.

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

Come potrei fare per espandere questo alla riga seguente, ad es

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

Risposte:


116

La concatenazione implicita potrebbe essere la soluzione più pulita:

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

Modifica Riflettendo, concordo sul fatto che il suggerimento di Todd di utilizzare le parentesi anziché la continuazione della linea sia migliore per tutte le ragioni che fornisce. L'unica esitazione che ho è che è relativamente facile confondere le stringhe tra parentesi con le tuple.


4
Questo è il motivo per cui mi sentivo come un idiota che pubblica la domanda. Saluti.
Federer,

8
Questa è la continuazione della linea sfuggendo alla linea di fondo, non solo una concatenazione implicita, e fino a poco tempo fa esplicitamente vietata in PEP8, sebbene ora ci sia un margine, ma NON per stringhe lunghe. La risposta di Todd qui sotto è corretta.
Aaron Hall

4
Mi piace PEP8, ma questo fa parte di PEP8 che non mi piace. Sento che la continuazione implicita è più chiara, a causa della possibilità di confusione con le tuple
monknomo,

1
Ricorda di non aggiungere spazi vuoti dopo \
Mrinal Saurabh il

cosa succede se la linea lunga si trova nel mezzo di una lunga stringa multi-linea?
Thayne,

299

Inoltre, poiché le costanti di stringa adiacenti vengono automaticamente concatenate, è possibile codificarle anche in questo modo:

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

Nota nessun segno più e ho aggiunto la virgola e lo spazio extra che seguono la formattazione del tuo esempio.

Personalmente non mi piacciono le barre rovesciate e ricordo di aver letto da qualche parte che il suo uso è in realtà deprecato a favore di questo modulo che è più esplicito. Ricorda "Esplicito è meglio che implicito".

Ritengo che la barra rovesciata sia meno chiara e meno utile perché in realtà sta sfuggendo al carattere di nuova riga. Non è possibile inserire un commento di fine riga dopo di esso, se necessario. È possibile farlo con costanti di stringa concatenate:

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

Ho usato una ricerca Google di "lunghezza della linea di Python" che restituisce il collegamento PEP8 come primo risultato, ma anche collegamenti a un altro buon post StackOverflow su questo argomento: " Perché Python PEP-8 dovrebbe specificare una lunghezza massima di 79 caratteri? "

Un'altra buona frase di ricerca sarebbe "continuazione della linea di pitone".


8
+1: "Personalmente non mi piacciono le barre rovesciate e ricordo di aver letto da qualche parte che il suo uso è in realtà deprecato a favore di questo modulo che è più esplicito. Ricorda" Esplicito è meglio che implicito ""
Alberto Megía,

13
Per tutti coloro che hanno una tupla e si chiedono perché. Non aggiungere qui le virgole alla fine delle righe, ciò comporterà una tupla, non una stringa. ;)
bugmenot123

7
L'aggiunta del carattere + non è più esplicita dell'esempio fornito? Considererei ancora questo implicito. cioè "str1" + "str2"piuttosto che"str1" "str2"
user1318135,

4
In realtà concordo sul fatto che il segno più sia più esplicito, ma fa una cosa diversa. Trasforma la stringa in un'espressione da valutare, anziché specificare una costante di stringa singola in un numero di pezzi. Non ne sono certo, ma penso che ciò avvenga durante l'analisi mentre l'espressione deve essere eseguita in un secondo momento. La differenza di velocità è probabilmente trascurabile a meno che non ce ne sia un numero enorme. Ma anche esteticamente preferisco la concatenazione automatica poiché è un carattere in disordine in meno per riga.
Todd,

4
Questa sintassi mantiene anche la possibilità di applicare la formattazione di stringhe come:('this is my really, really, really, really, really long {} ' 'that I'd really, really, really, like to {}').format(var1, var2))
Tim

16

Penso che la parola più importante nella tua domanda fosse "suggerisce".

Gli standard di codifica sono cose divertenti. Spesso la guida che forniscono ha una base davvero buona quando è stata scritta (ad es. La maggior parte dei terminali non è in grado di mostrare> 80 caratteri su una riga), ma col tempo diventano funzionalmente obsoleti, ma ancora rigidamente rispettati. Immagino che ciò che devi fare qui sia valutare i relativi meriti di "rompere" quel particolare suggerimento contro la leggibilità e la conservabilità del tuo codice.

Mi dispiace, questo non risponde direttamente alla tua domanda.


Sono totalmente d'accordo. Esiste una regola simile in stile Java che è diventata anche obsoleta (IMHO).
Iker Jimenez,

Sì, sono d'accordo, tuttavia Mi ha confuso il modo in cui mi atterrei in questo esempio particolare. Cerco sempre di mantenere classi, metodi a <80 caratteri, tuttavia direi che una stringa come questa non ha alcun effetto se non quello negativo.
Federer,

1
Devi anche valutare le tue preferenze personali rispetto allo standard di codifica a livello di comunità. Desideri che nuove persone possano entrare e familiarizzare con la formattazione del codice fin dal primo giorno.
Retracile

1
Lo so per me stesso, tendo a rispettare il limite di 80 caratteri solo perché continuo ancora a scrivere codice in IDLE e non mi piace il modo in cui gestisce lo scorrimento orizzontale. (Nessuna barra di scorrimento)
Tofystedeth

@retracile - sì, lo fai. Non sto dicendo "Devi ignorare la guida", piuttosto suggerendo che in alcuni casi la guida non è necessariamente lì per il bene della comunità. Non ero a conoscenza delle restrizioni di IDLE (come pubblicato da Tofystedeth) ma in quel caso c'è un argomento striong per seguire la convenzione.
ZombieSheep,

13

Hai perso uno spazio e probabilmente hai bisogno di un carattere di continuazione della linea, ad es. a \.

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

o anche:

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

Parens avrebbe funzionato anche al posto della continuazione della linea, ma rischieresti che qualcuno pensasse di avere una tupla e che avesse appena dimenticato una virgola. Prendi ad esempio:

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

contro:

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

Con la tipizzazione dinamica di Python, il codice può essere eseguito in entrambi i modi, ma produce risultati errati con quello che non intendevi.


2

Barra rovesciata:

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

o avvolgere in parentesi:

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

2
Si noti che il plus è necessario. Python concatena i letterali stringa che si susseguono.
bukzor,

2

Queste sono tutte ottime risposte, ma non sono riuscito a trovare un plug-in di editor che mi aiutasse a modificare stringhe "implicitamente concatenate", quindi ho scritto un pacchetto per semplificarmi.

Su pip (installa paragrafi) se chiunque vaga in questo vecchio thread vorrebbe dargli un'occhiata. Formatta le stringhe multilinea come HTML (comprime gli spazi bianchi, due nuove righe per un nuovo paragrafo, nessuna preoccupazione per gli spazi tra le righe).

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

diventa ...

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

Tutto si allinea facilmente con (Vim) 'gq'


0

Con un \puoi espandere le istruzioni su più righe:

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

dovrebbe funzionare.


0

Tendo a usare un paio di metodi non menzionati qui per specificare stringhe di grandi dimensioni, ma questi sono per scenari molto specifici. YMMV ...

  • Macchie di testo multilinea, spesso con token formattati (non proprio quello che stavi chiedendo, ma comunque utile):

    error_message = '''
    I generally like to see how my helpful, sometimes multi-line error
    messages will look against the left border.
    '''.strip()
  • Fai crescere la variabile pezzo per pezzo attraverso il metodo di interpolazione delle stringhe che preferisci:

    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.'
  • Leggilo da un file. PEP-8 non limita la lunghezza delle stringhe in un file; solo le righe del tuo codice. :)

  • Usa la forza bruta o il tuo editor per dividere la stringa in linee gestibili usando le nuove linee, quindi rimuovi tutte le nuove linee. (Simile alla prima tecnica che ho elencato):

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

0

Opzioni disponibili:

  • barra rovesciata :"foo" \ "bar"
  • segno più seguito da barra rovesciata :"foo" + \ "bar"
  • parentesi :
    • ("foo" "bar")
    • parentesi con segno più :("foo" + "bar")
    • PEP8, E502: la barra rovesciata è ridondante tra parentesi

Evitare

Evita le parentesi con la virgola: ("foo", "bar")che definisce 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
>>> 

0

Se devi inserire una stringa lunga letterale e vuoi che flake8 stia zitto, puoi usare le sue direttive di chiusura . Ad esempio, in una routine di test ho definito alcuni input CSV falsi. Ho scoperto che dividerlo su più righe che aveva righe sarebbe stato molto confuso, quindi ho deciso di aggiungere un # noqa: E501come segue:

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

-1

Ho usato textwrap.dedent in passato. È un po 'ingombrante, quindi preferisco le continuazioni di linea ora, ma se vuoi davvero il rientro del blocco, penso che sia grandioso.

Codice di esempio (in cui il trim deve eliminare il primo '\ n' con una sezione):

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

Spiegazione:

dedent calcola il rientro in base allo spazio bianco nella prima riga di testo prima di una nuova riga. Se volessi modificarlo, potresti facilmente reimplementarlo usando ilre modulo.

Questo metodo ha delle limitazioni in quanto le linee molto lunghe potrebbero essere ancora più lunghe di quanto desideri, nel qual caso altri metodi che concatenano le stringhe sono più adatti.


1
Invece di tagliare con x[1:]te puoi mettere una barra rovesciata dopo x = """per evitare la prima nuova riga.
Michael Dunn,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.