Wie man einen sehr langen String schreibt, der PEP8 entspricht und E501 verhindert


202

Da PEP8 vorschlägt, die 80-Spalten-Regel für Ihr Python-Programm zu unterschreiten, wie kann ich mich mit langen Zeichenfolgen daran halten, d. H.

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

Wie würde ich vorgehen, um dies auf die folgende Zeile zu erweitern, dh

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

Antworten:


116

Implizite Verkettung könnte die sauberste Lösung sein:

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

Bearbeiten Auf Reflexion Ich bin damit einverstanden , dass Todd Vorschlag zur Verwendung Klammern eher als Linienfortsetzungs ist besser für alle die Gründe , die er gibt. Das einzige Zögern, das ich habe, ist, dass es relativ einfach ist, in Klammern gesetzte Zeichenfolgen mit Tupeln zu verwechseln.


4
Deshalb fühlte ich mich wie ein Idiot, der die Frage stellt. Prost.
Federer

8
Dies ist eine Zeilenfortsetzung, indem die Endzeile verlassen wird, nicht nur eine implizite Verkettung, und bis vor kurzem in PEP8 ausdrücklich verboten, obwohl jetzt eine Zulage vorhanden ist, jedoch NICHT für lange Zeichenfolgen. Die Antwort von Todd unten ist richtig.
Aaron Hall

4
Ich mag PEP8, aber dies ist ein Teil von PEP8, den ich nicht mag. Ich
denke

1
Denken Sie daran, nach \
Mrinal Saurabh

Was ist, wenn sich die lange Zeile in der Mitte einer langen mehrzeiligen Zeichenfolge befindet?
Thayne

298

Da benachbarte Zeichenfolgenkonstanten automatisch verkettet werden, können Sie sie auch folgendermaßen codieren:

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

Beachten Sie kein Pluszeichen, und ich habe das zusätzliche Komma und Leerzeichen hinzugefügt, die der Formatierung Ihres Beispiels folgen.

Persönlich mag ich die Backslashes nicht, und ich erinnere mich, dass ich irgendwo gelesen habe, dass ihre Verwendung zugunsten dieser expliziteren Form tatsächlich veraltet ist. Denken Sie daran: "Explizit ist besser als implizit."

Ich halte den Backslash für weniger klar und weniger nützlich, da dies tatsächlich dem Newline-Zeichen entgeht. Es ist nicht möglich, einen Zeilenende-Kommentar danach zu setzen, falls dies erforderlich sein sollte. Dies ist mit verketteten Zeichenfolgenkonstanten möglich:

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

Ich habe eine Google-Suche nach "Python-Zeilenlänge" verwendet, die den PEP8-Link als erstes Ergebnis zurückgibt, aber auch Links zu einem anderen guten StackOverflow-Beitrag zu diesem Thema: " Warum sollte Python PEP-8 eine maximale Zeilenlänge von 79 Zeichen angeben? "

Ein weiterer guter Suchbegriff wäre "Python Line Continuation".


8
+1: "Ich persönlich mag die Backslashes nicht und ich erinnere mich, dass ich irgendwo gelesen habe, dass ihre Verwendung zugunsten dieser expliziteren Form tatsächlich veraltet ist. Denken Sie daran," Explizit ist besser als implizit. ""
Alberto Megía

13
Für alle, die ein Tupel bekommen und sich fragen warum. Fügen Sie hier keine Kommas am Ende der Zeilen ein, da dies zu einem Tupel und nicht zu einer Zeichenfolge führt. ;)
bugmenot123

7
Ist das Hinzufügen des Zeichens + nicht expliziter als im angegebenen Beispiel? Ich würde das immer noch als implizit betrachten. dh "str1" + "str2"eher als"str1" "str2"
user1318135

4
Ich stimme tatsächlich zu, dass das Pluszeichen expliziter ist, aber es macht eine andere Sache. Es verwandelt die Zeichenfolge in einen auszuwertenden Ausdruck, anstatt eine einzelne Zeichenfolgenkonstante in mehreren Teilen anzugeben. Ich bin nicht sicher, aber ich denke, dies geschieht während des Parsens, während der Ausdruck später ausgeführt werden muss. Der Geschwindigkeitsunterschied ist wahrscheinlich vernachlässigbar, es sei denn, es gibt eine große Anzahl von ihnen. Aber auch ästhetisch bevorzuge ich die automatische Verkettung, da es sich um ein weniger überladenes Zeichen pro Zeile handelt.
Todd

4
Diese Syntax bietet auch die Möglichkeit, Zeichenfolgenformatierungen wie die folgenden anzuwenden:('this is my really, really, really, really, really long {} ' 'that I'd really, really, really, like to {}').format(var1, var2))
Tim

16

Ich denke, das wichtigste Wort in Ihrer Frage war "schlägt vor".

Codierungsstandards sind lustige Dinge. Oft haben die von ihnen bereitgestellten Anleitungen eine wirklich gute Grundlage, als sie geschrieben wurden (z. B. können die meisten Terminals nicht mehr als 80 Zeichen in einer Zeile anzeigen), aber im Laufe der Zeit werden sie funktional veraltet, werden aber immer noch strikt eingehalten. Ich denke, was Sie hier tun müssen, ist, die relativen Vorzüge des "Brechens" dieses bestimmten Vorschlags gegen die Lesbarkeit und Wartbarkeit Ihres Codes abzuwägen.

Entschuldigung, dies beantwortet Ihre Frage nicht direkt.


Ich bin vollkommen einverstanden. Es gibt eine ähnliche Regel im Java-Stil, die ebenfalls veraltet ist (IMHO).
Iker Jimenez

Ja, ich stimme zu, aber es hat mir den Kopf zerbrochen, wie ich mich in diesem speziellen Beispiel daran halten würde. Ich versuche immer, Klassen und Methoden auf <80 Zeichen zu beschränken, aber ich würde sagen, dass eine solche Zeichenfolge keine andere Wirkung hat als vielleicht eine negative.
Federer

1
Sie müssen auch Ihre persönlichen Vorlieben gegen den gemeinschaftsweiten Codierungsstandard abwägen. Sie möchten, dass neue Leute vom ersten Tag an mit der Code-Formatierung vertraut werden.
Retracile

1
Ich weiß für mich selbst, dass ich mich eher an die 80-Zeichen-Grenze halte, nur weil ich den größten Teil meiner Codierung immer noch in IDLE mache und die Art und Weise, wie horizontales Scrollen funktioniert, nicht gefällt. (Keine Bildlaufleiste)
Tofystedeth

@retracile - ja, das tust du. Ich sage nicht "Sie müssen die Anleitung ignorieren", sondern schlage vor, dass die Anleitung in einigen Fällen nicht unbedingt zum Wohl der Gemeinschaft da ist. Ich war mir der Einschränkungen von IDLE (wie von Tofystedeth veröffentlicht) nicht bewusst, aber in diesem Fall gibt es ein striktes Argument für die Einhaltung der Konvention.
ZombieSheep

13

Sie haben ein Leerzeichen verloren und benötigen wahrscheinlich ein Zeilenfortsetzungszeichen, d. H. a \.

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

oder auch:

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

Parens würde auch anstelle der Zeilenfortsetzung funktionieren, aber Sie riskieren jemanden, der denkt, Sie wollten ein Tupel haben und haben gerade ein Komma vergessen. Nimm zum Beispiel:

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

gegen:

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

Bei der dynamischen Typisierung von Python kann der Code in beide Richtungen ausgeführt werden, führt jedoch zu falschen Ergebnissen mit dem von Ihnen nicht beabsichtigten.


2

Backslash:

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

oder in Parens einwickeln:

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

2
Beachten Sie, dass das Plus notwendig ist. Python verkettet aufeinanderfolgende Zeichenfolgenliterale.
Bukzor

2

Dies sind alles gute Antworten, aber ich konnte kein Editor-Plugin finden, das mir beim Bearbeiten von "implizit verketteten" Zeichenfolgen helfen würde. Deshalb habe ich ein Paket geschrieben, um es mir leichter zu machen.

Auf pip (Absätze installieren), wenn jemand, der diesen alten Thread durchwandert, ihn überprüfen möchte. Formatiert mehrzeilige Zeichenfolgen wie HTML (komprimiert Leerzeichen, zwei neue Zeilen für einen neuen Absatz, keine Sorge um Leerzeichen zwischen Zeilen).

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

wird ...

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

Alles passt leicht zu (Vim) 'gq'


0

Mit a können \Sie Anweisungen auf mehrere Zeilen erweitern:

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

sollte arbeiten.


0

Ich neige dazu, einige Methoden zu verwenden, die hier nicht erwähnt werden, um große Zeichenfolgen anzugeben, aber diese sind für sehr spezifische Szenarien. YMMV ...

  • Mehrzeilige Textblobs, oft mit formatierten Token (nicht ganz das, was Sie gefragt haben, aber dennoch nützlich):

    error_message = '''
    I generally like to see how my helpful, sometimes multi-line error
    messages will look against the left border.
    '''.strip()
  • Erweitern Sie die Variable Stück für Stück durch eine beliebige String-Interpolationsmethode, die Sie bevorzugen:

    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.'
  • Lesen Sie es aus einer Datei. PEP-8 begrenzt die Länge der Zeichenfolgen in einer Datei nicht. nur die Zeilen Ihres Codes. :) :)

  • Verwenden Sie Brute-Force oder Ihren Editor, um die Zeichenfolge mithilfe von Zeilenumbrüchen in verwaltbare Zeilen aufzuteilen, und entfernen Sie dann alle Zeilenumbrüche. (Ähnlich wie bei der ersten Technik, die ich aufgelistet habe):

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

0

Verfügbare Optionen:

  • Backslash :"foo" \ "bar"
  • Pluszeichen gefolgt von Backslash :"foo" + \ "bar"
  • Klammern :
    • ("foo" "bar")
    • Klammern mit Pluszeichen :("foo" + "bar")
    • PEP8, E502: Der Backslash zwischen Klammern ist redundant

Vermeiden

Vermeiden Sie Klammern mit Komma: ("foo", "bar")Dies definiert ein Tupel.


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

Wenn Sie ein langes String-Literal einfügen müssen und flake8 herunterfahren soll, können Sie die Anweisungen zum Herunterfahren verwenden . Zum Beispiel habe ich in einer Testroutine eine gefälschte CSV-Eingabe definiert. Ich fand, dass das Aufteilen auf mehr Zeilen mit Zeilen sehr verwirrend wäre, und entschied mich daher, # noqa: E501Folgendes wie folgt hinzuzufügen :

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

Ich habe in der Vergangenheit textwrap.dedent verwendet. Es ist etwas umständlich, deshalb bevorzuge ich jetzt Zeilenfortsetzungen, aber wenn Sie wirklich den Blockeinzug wollen, finde ich das großartig.

Beispielcode (wobei der Zuschnitt darin besteht, das erste '\ n' mit einem Slice zu entfernen):

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

Erläuterung:

dedent berechnet den Einzug basierend auf dem Leerraum in der ersten Textzeile vor einer neuen Zeile. Wenn Sie es optimieren möchten, können Sie es mithilfe des reModuls problemlos erneut implementieren .

Diese Methode hat Einschränkungen, da sehr lange Zeilen möglicherweise noch länger sind als gewünscht. In diesem Fall sind andere Methoden, die Zeichenfolgen verketten, besser geeignet.


1
Anstatt zu trimmen x[1:], können Sie nachher einen Backslash setzen x = """, um den ersten Zeilenumbruch zu vermeiden.
Michael Dunn
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.