Comment puis-je rompre cette longue ligne en Python?

176

Comment feriez-vous pour formater une longue ligne comme celle-ci? Je souhaite que la largeur ne dépasse pas 80 caractères:

logger.info("Skipping {0} because its thumbnail was already in our system as {1}.".format(line[indexes['url']], video.title))

Est-ce ma meilleure option?

url = "Skipping {0} because its thumbnail was already in our system as {1}."
logger.info(url.format(line[indexes['url']], video.title))
Gattster
la source
1
Cela semble être une bonne option. Qu'est-ce que tu n'aimes pas?
Hamish Grubijan
2
Un peu subjectif, non? :)
Adam Woś
1
en relation: stackoverflow.com/questions/1940710/… (concaténation de chaînes en python)
jldupont
14
Vous pouvez enregistrer un caractère en supprimant le mauvais 'dans "c'est".
jball
2
indexes: le pluriel correct de indexest indices.
Scruffy

Réponses:

336

C'est un début. Ce n'est pas une mauvaise pratique de définir vos chaînes plus longues en dehors du code qui les utilise. C'est un moyen de séparer les données et le comportement. Votre première option est de joindre implicitement les littéraux de chaîne en les rendant adjacents les uns aux autres:

("This is the first line of my text, "
"which will be joined to a second.")

Ou avec des continuations de fin de ligne, ce qui est un peu plus fragile, car cela fonctionne:

"This is the first line of my text, " \
"which will be joined to a second."

Mais cela ne:

"This is the first line of my text, " \ 
"which will be joined to a second."

Regarde la différence? Non? Eh bien, vous ne le ferez pas non plus quand c'est votre code.

L'inconvénient de la jointure implicite est qu'elle ne fonctionne qu'avec des chaînes littérales, pas avec des chaînes extraites de variables, donc les choses peuvent devenir un peu plus velues lorsque vous refactorisez. En outre, vous ne pouvez interpoler la mise en forme que sur la chaîne combinée dans son ensemble.

Alternativement, vous pouvez rejoindre explicitement en utilisant l'opérateur de concaténation ( +):

("This is the first line of my text, " + 
"which will be joined to a second.")

Explicite vaut mieux qu'implicite, comme le dit le zen de python, mais cela crée trois chaînes au lieu d'une, et utilise deux fois plus de mémoire: il y a les deux que vous avez écrites, plus une qui est les deux réunies, donc vous faut savoir quand ignorer le zen. L'avantage est que vous pouvez appliquer la mise en forme à l'une des sous-chaînes séparément sur chaque ligne, ou à l'ensemble du lot en dehors des parenthèses.

Enfin, vous pouvez utiliser des chaînes entre guillemets triples:

"""This is the first line of my text
which will be joined to a second."""

C'est souvent mon préféré, bien que son comportement soit légèrement différent car la nouvelle ligne et tout espace blanc de début sur les lignes suivantes apparaîtront dans votre chaîne finale. Vous pouvez éliminer la nouvelle ligne avec une barre oblique inverse d'échappement.

"""This is the first line of my text \
which will be joined to a second."""

Cela pose le même problème que la même technique ci-dessus, en ce que le code correct ne diffère du code incorrect que par des espaces invisibles.

Laquelle est "la meilleure" dépend de votre situation particulière, mais la réponse n'est pas simplement esthétique, mais l'un des comportements subtilement différents.

jcdyer
la source
26
Le compilateur CPython optimise autant que possible les opérations littérales, ce qui signifie que l'ajout de deux littéraux de chaîne ne produit qu'un seul littéral de chaîne dans le bytecode.
Ignacio Vazquez-Abrams
2
Bien que toutes les réponses que j'ai reçues soient utiles, les vôtres m'aident certainement à comprendre toutes les façons de rompre les liens. Est-ce que le problème avec la ligne "\" se terminant par un espace après elle?
Gattster
1
Je ne peux pas voir la différence ici, mais c'est principalement à cause de la coloration syntaxique plutôt primitive de SO. (Certains codes parfaitement bons sont pratiquement illisibles sur SO, mais uniquement parce qu'ils ne sont pas dans un langage dont la syntaxe est très proche de C.) . :-)
Ken
1
@KhurshidAlam vous pouvez utiliser des guillemets simples 'pour contenir cette chaîne, ou échapper les guillemets doubles à l'intérieur de votre chaîne, ou utiliser les triples guillemets doubles """. Le problème avec les chaînes entre guillemets contenant des guillemets est le même que vous utilisiez une seule ligne ou plusieurs lignes pour définir la chaîne littérale.
hugovdberg le
1
Mon éditeur supprime toujours les espaces de fin. Je vous recommande d'activer le même paramètre. Bien sûr, l'espace blanc sur la nouvelle ligne fait toujours partie de la chaîne, alors j'ai fini par utiliser +.
ThaJay
46

Les littéraux de chaîne consécutifs sont joints par le compilateur et les expressions entre parenthèses sont considérées comme une seule ligne de code:

logger.info("Skipping {0} because it's thumbnail was "
  "already in our system as {1}.".format(line[indexes['url']],
  video.title))
Ignacio Vazquez-Abrams
la source
11

Personnellement, je n'aime pas accrocher des blocs ouverts, alors je le formaterais comme suit:

logger.info(
    'Skipping {0} because its thumbnail was already in our system as {1}.'
    .format(line[indexes['url']], video.title)
)

En général, je ne me donnerais pas la peine de lutter trop dur pour que le code tienne exactement dans une ligne de 80 colonnes. Cela vaut la peine de maintenir la longueur de la ligne à des niveaux raisonnables, mais la limite de 80 durs appartient au passé.

bobince
la source
8
Ce n'est pas vraiment une chose du passé. La bibliothèque standard Python utilise toujours PEP8 comme guide de style, donc la règle existe toujours et beaucoup de gens (moi y compris) la suivent. C'est un endroit pratique pour tracer la ligne.
Devin Jeanpierre
3
Je me demande combien de projets suivent encore la règle des 80 caractères. Pour la taille moyenne de la fenêtre que j'utilise, je pense que 100-120 est plus productif pour moi que 80 caractères.
Gattster le
1
Oui, c'est à peu près la longueur de la ligne que j'utilise aussi, bien que [horreur! sacrilège!] J'utilise une police proportionnelle, donc la longueur exacte de la ligne n'est pas si critique. Il s'agit plus de savoir combien de logique sur une seule ligne est lisible que de combien de caractères, en tant que tel ... si j'ai une longue chaîne de données que personne n'a besoin de lire, je suis heureux de la laisser déborder 120.
bobince
Polices proportionnelles pour le code - je suis avec vous, mon frère. À en juger par le dégoût que tout le monde avec qui j'ai déjà travaillé a eu pour eux, le monde n'est pas prêt.
jlarcombe
4
~ 80 caractères facilitent également la comparaison de 2 fichiers côte à côte sur le même écran. De plus, si vous déboguez quelque chose lors d'une grave urgence sur la console d'un serveur, vous apprécierez vraiment la limite de 80 caractères! :)
Mick T
4

Vous pouvez utiliser le module textwrap pour le diviser en plusieurs lignes

import textwrap
str="ABCDEFGHIJKLIMNO"
print("\n".join(textwrap.wrap(str,8)))

ABCDEFGH
IJKLIMNO

De la documentation :

habillage de texte. wrap (text [, width [, ...]])
Enveloppe le paragraphe unique dans le texte (une chaîne) de sorte que chaque ligne ne dépasse pas la largeur des caractères. Renvoie une liste de lignes de sortie, sans sauts de ligne finaux.

Les arguments de mot-clé facultatifs correspondent aux attributs d'instance de TextWrapper, documentés ci-dessous. la largeur par défaut est 70.

Voir la TextWrapper.wrap()méthode pour plus de détails sur le comportement de wrap ().

Saurabh
la source
2

Pour quiconque essaie également d'appeler .format()une longue chaîne et ne peut pas utiliser certaines des techniques d'enroulement de chaîne les plus populaires sans interrompre l' .format(appel suivant, vous pouvez le faire à la str.format("", 1, 2)place de "".format(1, 2). Cela vous permet de casser la corde avec la technique de votre choix. Par exemple:

logger.info("Skipping {0} because its thumbnail was already in our system as {1}.".format(line[indexes['url']], video.title))

peut être

logger.info(str.format(("Skipping {0} because its thumbnail was already"
+ "in our system as {1}"), line[indexes['url']], video.title))

Sinon, la seule possibilité est d'utiliser des continuations de fin de ligne, dont je ne suis personnellement pas fan.

Simon Alford
la source