Comment écrire une chaîne très longue conforme à PEP8 et empêcher E501

203

Comme PEP8 suggère de rester en dessous de la règle des 80 colonnes pour votre programme python, comment puis-je respecter cela avec de longues chaînes, c'est-à-dire

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

Comment pourrais-je étendre cela à la ligne suivante, c'est-à-dire

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

Réponses:

116

La concaténation implicite pourrait être la solution la plus propre:

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

Modifier Après réflexion, je conviens que la suggestion de Todd d'utiliser des crochets plutôt que la continuation de ligne est meilleure pour toutes les raisons qu'il donne. La seule hésitation que j'ai, c'est qu'il est relativement facile de confondre les chaînes entre crochets et les tuples.

Michael Dunn
la source
4
C'est pourquoi je me sentais comme un idiot en posant la question. À votre santé.
Federer
8
Il s'agit de la continuation de ligne en échappant à la ligne de fin, et pas seulement à la concaténation implicite, et jusqu'à très récemment explicitement interdite dans PEP8, bien qu'il existe maintenant une allocation, mais PAS pour les chaînes longues. La réponse de Todd ci-dessous est correcte.
Aaron Hall
4
J'aime PEP8, mais cela fait partie de PEP8 que je n'aime pas. J'ai l'impression que la suite implicite est plus claire, en raison de la possibilité de confusion avec les tuples
monknomo
1
N'oubliez pas de ne pas ajouter d'espaces vides après \
Mrinal Saurabh
que faire si la longue ligne se trouve au milieu d'une longue chaîne multi-lignes?
Thayne
299

De plus, comme les constantes de chaînes voisines sont automatiquement concaténées, vous pouvez également les coder comme ceci:

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

Remarquez pas de signe plus, et j'ai ajouté la virgule et l'espace supplémentaires qui suivent la mise en forme de votre exemple.

Personnellement, je n'aime pas les barres obliques inverses, et je me souviens avoir lu quelque part que son utilisation est en fait déconseillée au profit de cette forme qui est plus explicite. Rappelez-vous que "explicite vaut mieux qu'implicite".

Je considère que la barre oblique inverse est moins claire et moins utile car elle échappe en fait au caractère de nouvelle ligne. Il n'est pas possible de mettre un commentaire de fin de ligne après si cela est nécessaire. Il est possible de le faire avec des constantes de chaîne concaténées:

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

J'ai utilisé une recherche Google de «longueur de ligne python» qui renvoie le lien PEP8 comme premier résultat, mais aussi des liens vers un autre bon article StackOverflow sur ce sujet: « Pourquoi Python PEP-8 devrait-il spécifier une longueur de ligne maximale de 79 caractères? "

Une autre bonne expression de recherche serait "continuation de la ligne python".

Todd
la source
8
+1: "Personnellement, je n'aime pas les barres obliques inverses, et je me souviens avoir lu quelque part que son utilisation est en fait déconseillée au profit de cette forme qui est plus explicite. N'oubliez pas" Explicite vaut mieux qu'implicite. ""
Alberto Megía
13
Pour tous ceux qui obtiennent un tuple et se demandent pourquoi. N'ajoutez pas de virgules à la fin des lignes ici, cela entraînera un tuple, pas une chaîne. ;)
bugmenot123
7
L'ajout du caractère + n'est-il pas plus explicite que l'exemple donné? Je considérerais toujours cela implicite. c'est-à-dire "str1" + "str2"plutôt que"str1" "str2"
user1318135
4
En fait, je suis d'accord que le signe plus est plus explicite, mais cela fait une chose différente. Il transforme la chaîne en une expression à évaluer, plutôt que de spécifier une constante de chaîne unique en plusieurs morceaux. Je ne suis pas certain mais je pense que cela se fait pendant l'analyse alors que l'expression doit être exécutée plus tard. La différence de vitesse est probablement négligeable à moins qu'il y en ait un grand nombre. Mais aussi sur le plan esthétique, je préfère la concaténation automatique car il s'agit d'un caractère encombrant de moins par ligne.
Todd
4
Cette syntaxe conserve également la possibilité d'appliquer un formatage de chaîne comme:('this is my really, really, really, really, really long {} ' 'that I'd really, really, really, like to {}').format(var1, var2))
Tim
16

Je pense que le mot le plus important dans votre question était "suggère".

Les normes de codage sont des choses amusantes. Souvent, les conseils qu'ils fournissent ont une très bonne base quand ils ont été écrits (par exemple, la plupart des terminaux ne peuvent pas afficher> 80 caractères sur une ligne), mais au fil du temps, ils deviennent obsolètes sur le plan fonctionnel, mais restent strictement respectés. Je suppose que ce que vous devez faire ici est de soupeser les mérites relatifs de "casser" cette suggestion particulière par rapport à la lisibilité et la mainatinabilité de votre code.

Désolé, cela ne répond pas directement à votre question.

ZombieSheep
la source
Je suis tout à fait d'accord. Il existe une règle de style Java similaire qui est également devenue obsolète (à mon humble avis).
Iker Jimenez
Oui, je suis d'accord, mais ça me fait peur de voir comment je me conformerais à cet exemple particulier. J'essaie toujours de garder les classes, les méthodes à <80 caractères, mais je dirais qu'une chaîne comme celle-ci n'a aucun effet autre que peut-être négatif.
Federer
1
Vous devez également évaluer vos préférences personnelles par rapport à la norme de codage à l'échelle de la communauté. Vous voulez que de nouvelles personnes puissent entrer et être à l'aise avec le formatage du code dès le premier jour.
retracile
1
Je sais par moi-même, j'ai tendance à m'en tenir à la limite de 80 caractères juste parce que je fais encore la plupart de mon codage en IDLE et je n'aime pas la façon dont il gère le défilement horizontal. (Pas de barre de défilement)
Tofystedeth
@retracile - oui, vous le faites. Je ne dis pas "Vous devez ignorer les conseils", mais plutôt suggérer que dans certains cas, les conseils ne sont pas nécessairement là pour le bien de la communauté. Je n'étais pas au courant des restrictions d'IDLE (telles que publiées par Tofystedeth) mais dans ce cas, il y a un argument striong pour suivre la convention.
ZombieSheep
13

Vous avez perdu un espace et vous avez probablement besoin d'un caractère de continuation de ligne, c'est-à-dire. a \.

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

ou même:

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

Parens fonctionnerait également à la place de la continuation de la ligne, mais vous risquez que quelqu'un pense que vous avez l'intention d'avoir un tuple et que vous venez d'oublier une virgule. Prenez par exemple:

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

contre:

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

Avec le typage dynamique de Python, le code peut s'exécuter dans les deux sens, mais produire des résultats incorrects avec celui que vous ne vouliez pas.

retracile
la source
2

Barre oblique inverse:

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

ou envelopper de parens:

s = ("this is my really, really, really, really, really, really" + 
    "really long string that I'd like to shorten.")
récursif
la source
2
Notez que le plus est nécessaire. Python concatène les littéraux de chaîne qui se succèdent.
bukzor
2

Ce sont toutes d'excellentes réponses, mais je n'ai pas trouvé de plugin d'éditeur qui m'aiderait à éditer des chaînes "implicitement concaténées", j'ai donc écrit un package pour me faciliter la tâche.

Sur pip (installez les paragraphes) si celui qui se promène sur ce vieux fil voudrait le vérifier. Formate les chaînes multi-lignes comme le fait HTML (compresser les espaces, deux nouvelles lignes pour un nouveau paragraphe, pas de soucis pour les espaces entre les lignes).

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

devient ...

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

Tout s'aligne facilement avec (Vim) 'gq'

Shay
la source
0

Avec un, \vous pouvez étendre les instructions à plusieurs lignes:

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

devrait marcher.

Ikke
la source
0

J'ai tendance à utiliser quelques méthodes non mentionnées ici pour spécifier de grandes chaînes, mais ce sont des scénarios très spécifiques. YMMV ...

  • Blobs de texte sur plusieurs lignes, souvent avec des jetons formatés (pas tout à fait ce que vous demandiez, mais toujours utiles):

    error_message = '''
    I generally like to see how my helpful, sometimes multi-line error
    messages will look against the left border.
    '''.strip()
  • Développez la variable pièce par pièce selon la méthode d'interpolation de chaîne que vous préférez:

    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.'
  • Lisez-le à partir d'un fichier. PEP-8 ne limite pas la longueur des chaînes dans un fichier; juste les lignes de votre code. :)

  • Utilisez la force brute ou votre éditeur pour diviser la chaîne en lignes manageables à l'aide de sauts de ligne, puis supprimez tous les sauts de ligne. (Similaire à la première technique que j'ai listée):

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

Options disponibles:

  • barre oblique inverse :"foo" \ "bar"
  • signe plus suivi d'une barre oblique inverse :"foo" + \ "bar"
  • crochets :
    • ("foo" "bar")
    • crochets avec signe plus :("foo" + "bar")
    • PEP8, E502: la barre oblique inverse est redondante entre parenthèses

Éviter

Évitez les crochets avec une virgule: ("foo", "bar")qui définit un tuple.


>>> 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
la source
0

Si vous devez insérer un littéral de chaîne longue et que flake8 se ferme, vous pouvez utiliser ses directives de fermeture . Par exemple, dans une routine de test, j'ai défini de fausses entrées CSV. J'ai trouvé que le fractionner sur plus de lignes qu'il y avait de lignes serait très déroutant, j'ai donc décidé d'ajouter un # noqa: E501comme suit:

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
la source
-1

J'ai utilisé textwrap.dedent dans le passé. C'est un peu lourd donc je préfère les continuations de ligne maintenant mais si vous voulez vraiment le retrait de bloc, je pense que c'est super.

Exemple de code (où la garniture consiste à se débarrasser du premier '\ n' avec une tranche):

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

Explication:

dedent calcule l'indentation en fonction de l'espace blanc dans la première ligne de texte avant une nouvelle ligne. Si vous vouliez le modifier, vous pouvez facilement le réimplémenter en utilisant lere module.

Cette méthode a des limites dans la mesure où de très longues lignes peuvent toujours être plus longues que vous le souhaitez, auquel cas d'autres méthodes de concaténation de chaînes conviennent mieux.

MrMas
la source
1
Plutôt que de couper avec, x[1:]vous pouvez mettre une barre oblique inverse après x = """pour éviter la première nouvelle ligne.
Michael Dunn