Quelle est l'indentation appropriée pour Python chaînes multilignes dans une fonction?
def method():
string = """line one
line two
line three"""
ou
def method():
string = """line one
line two
line three"""
ou autre chose?
Il est plutôt étrange de voir la chaîne suspendue à l'extérieur de la fonction dans le premier exemple.
Vous voulez probablement vous aligner avec le """
def foo():
string = """line one
line two
line three"""
Puisque les nouvelles lignes et les espaces sont inclus dans la chaîne elle-même, vous devrez la post-traiter. Si vous ne voulez pas faire cela et que vous avez beaucoup de texte, vous voudrez peut-être le stocker séparément dans un fichier texte. Si un fichier texte ne fonctionne pas bien pour votre application et que vous ne voulez pas post-traiter, j'irais probablement avec
def foo():
string = ("this is an "
"implicitly joined "
"string")
Si vous souhaitez post-traiter une chaîne multiligne pour supprimer les parties inutiles, vous devez envisager le module textwrap
ou la technique de post-traitement des docstrings présentée dans PEP 257 :
def trim(docstring):
if not docstring:
return ''
# Convert tabs to spaces (following the normal Python rules)
# and split into a list of lines:
lines = docstring.expandtabs().splitlines()
# Determine minimum indentation (first line doesn't count):
indent = sys.maxint
for line in lines[1:]:
stripped = line.lstrip()
if stripped:
indent = min(indent, len(line) - len(stripped))
# Remove indentation (first line is special):
trimmed = [lines[0].strip()]
if indent < sys.maxint:
for line in lines[1:]:
trimmed.append(line[indent:].rstrip())
# Strip off trailing and leading blank lines:
while trimmed and not trimmed[-1]:
trimmed.pop()
while trimmed and not trimmed[0]:
trimmed.pop(0)
# Return a single string:
return '\n'.join(trimmed)
La fonction textwrap.dedent
permet de commencer par l’indentation correcte dans la source , puis de la supprimer du texte. Avant utilisation.
Le compromis, comme l'ont noté d'autres personnes, est qu'il s'agit d'un appel de fonction supplémentaire au littéral. tenez compte de cela lorsque vous décidez où placer ces littéraux dans votre code.
_import textwrap
def frobnicate(param):
""" Frobnicate the scrognate param.
The Weebly-Ruckford algorithm is employed to frobnicate
the scrognate to within an inch of its life.
"""
prepare_the_comfy_chair(param)
log_message = textwrap.dedent("""\
Prepare to frobnicate:
Here it comes...
Any moment now.
And: Frobnicate!""")
weebly(param, log_message)
ruckford(param)
_
La fin _\
_ dans le littéral du message de journal permet de s’assurer que le saut de ligne n’est pas dans le littéral; De cette façon, le littéral ne commence pas par une ligne vide, mais par la ligne complète suivante.
La valeur renvoyée par _textwrap.dedent
_ est la chaîne en entrée avec toutes les indentations d'espacement les plus communes précédantes supprimées sur chaque ligne de la chaîne. La valeur _log_message
_ ci-dessus sera donc:
_Prepare to frobnicate:
Here it comes...
Any moment now.
And: Frobnicate!
_
Utilisez inspect.cleandoc
comme suit:
_def method():
string = inspect.cleandoc("""
line one
line two
line three""")
_
L'indentation relative sera maintenue comme prévu.
Remarque: Il est judicieux d'indenter des blocs de code logiques dans son contexte associé afin de clarifier la structure. Par exemple. la chaîne multiligne appartenant à la variable
string
.
Une option qui semble manquer aux autres réponses (mentionnée au fond d'un commentaire de naxa) est la suivante:
def foo():
string = ("line one\n" # Add \n in the string
"line two" "\n" # Add "\n" after the string
"line three\n")
Cela permettra un alignement correct, joignera les lignes implicitement et conservera le décalage de ligne, ce qui est pour moi l’une des raisons pour lesquelles j’aimerais quand même utiliser des chaînes multilignes.
Il ne nécessite aucun post-traitement, mais vous devez ajouter manuellement le \n
à un endroit donné où vous voulez que la ligne se termine. Soit en ligne ou en tant que chaîne séparée après. Ce dernier est plus facile à copier-coller.
Quelques autres options. Dans Ipython avec pylab activé, dedent est déjà dans l’espace de noms. J'ai vérifié et c'est de matplotlib. Ou il peut être importé avec:
from matplotlib.cbook import dedent
Dans la documentation, il est indiqué qu’il est plus rapide que l’équivalent textwrap et que lors de mes tests sous ipython, il est effectivement 3 fois plus rapide en moyenne avec mes tests rapides. Il a également l'avantage de supprimer toutes les lignes vides en tête, ce qui vous permet d'être flexible dans la construction de la chaîne:
"""
line 1 of string
line 2 of string
"""
"""\
line 1 of string
line 2 of string
"""
"""line 1 of string
line 2 of string
"""
L'utilisation de Matplotlib dédiée à ces trois exemples donnera le même résultat raisonnable. La fonction déduction textwrap aura une première ligne vide avec le 1er exemple.
Le désavantage évident est que textwrap est dans une bibliothèque standard alors que matplotlib est un module externe.
Certains compromis ici ... les fonctions dédiées rendent votre code plus lisible là où les chaînes sont définies, mais nécessitent un traitement ultérieur pour obtenir la chaîne au format utilisable. Dans docstrings, il est évident que vous devez utiliser le bon retrait car la plupart des utilisations de docstring effectueront le traitement requis.
Lorsque j'ai besoin d'une chaîne non longue dans mon code, je trouve le code ci-après, certes laid, dans lequel je laisse la chaîne longue tomber de l'indentation. Il échoue définitivement sur "Le beau est meilleur que le laid", mais on pourrait dire que c'est plus simple et plus explicite que l'alternative dédent.
def example():
long_string = '''\
Lorem ipsum dolor sit amet, consectetur adipisicing
elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip.\
'''
return long_string
print example()
Si vous voulez une solution rapide et facile et que vous évitiez de taper des nouvelles lignes, vous pouvez opter pour une liste, par exemple:
def func(*args, **kwargs):
string = '\n'.join([
'first line of very long string and',
'second line of the same long thing and',
'third line of ...',
'and so on...',
])
print(string)
return
Je préfère
def method():
string = \
"""\
line one
line two
line three\
"""
ou
def method():
string = """\
line one
line two
line three\
"""
Mes deux cents, échapper à la fin de la ligne pour obtenir les tirets:
def foo():
return "{}\n"\
"freq: {}\n"\
"temp: {}\n".format( time, freq, temp )
La première option est la bonne - avec l'indentation incluse. C'est dans le style python - fournit la lisibilité du code.
Pour l'afficher correctement:
print string.lstrip()
Je suis venu ici à la recherche d'un simple 1-liner pour supprimer/corriger le niveau d'identification de la docstring pour l'impression, sans le rendre désordonné, par exemple en le faisant "accrocher" en dehors de la fonction "dans le script.
Voici ce que j'ai fini par faire:
import string
def myfunction():
"""
line 1 of docstring
line 2 of docstring
line 3 of docstring"""
print str(string.replace(myfunction.__doc__,'\n\t','\n'))[1:]
Évidemment, si vous indentez avec des espaces (par exemple 4) plutôt que la touche de tabulation, utilisez quelque chose comme ceci à la place:
print str(string.replace(myfunction.__doc__,'\n ','\n'))[1:]
Et vous n'avez pas besoin de supprimer le premier caractère si vous préférez que votre docstring ressemble à ceci:
"""line 1 of docstring
line 2 of docstring
line 3 of docstring"""
print string.replace(myfunction.__doc__,'\n\t','\n')
Cela dépend de la façon dont vous voulez que le texte soit affiché. Si vous souhaitez que tout soit aligné à gauche, formatez-le comme dans le premier extrait de code ou parcourez les lignes en supprimant tout l'espace.
Pour les chaînes, vous pouvez juste après traiter la chaîne. Pour docstrings, vous devez plutôt traiter la fonction après. Voici une solution pour les deux qui est toujours lisible.
class Lstrip(object):
def __rsub__(self, other):
import re
return re.sub('^\n', '', re.sub('\n$', '', re.sub('\n\s+', '\n', other)))
msg = '''
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
est laborum.
''' - Lstrip()
print msg
def lstrip_docstring(func):
func.__doc__ = func.__doc__ - Lstrip()
return func
@lstrip_docstring
def foo():
'''
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
est laborum.
'''
pass
print foo.__doc__