web-dev-qa-db-fra.com

Python - write () versus writeelines () et chaînes concaténées

Donc j'apprends Python. Je suis en train de parcourir les leçons et j'ai rencontré un problème où je devais condenser un grand nombre de target.write() en une seule write(), tout en ayant un "\n" entre chaque variable d'entrée utilisateur (l'objet de write()).

Je suis venu avec:

nl = "\n"
lines = line1, nl, line2, nl, line3, nl
textdoc.writelines(lines)

Si j'essaie de faire:

textdoc.write(lines)

Je reçois une erreur. Mais si je tape:

textdoc.write(line1 + "\n" + line2 + ....)

Ensuite ça marche bien. Pourquoi suis-je incapable d'utiliser une chaîne pour une nouvelle ligne dans write() mais je peux l'utiliser dans writelines()?

Python 2.7 Lorsque j'ai cherché sur Google, la plupart des ressources que j'ai trouvées étaient bien au-dessus de ma tête, je suis toujours un laïc.

103
AbeLinkon
  • writelines attend un itérable de chaînes
  • write attend une seule chaîne.

line1 + "\n" + line2 fusionne ces chaînes en une seule chaîne avant de les transmettre à write.

Notez que si vous avez plusieurs lignes, vous pouvez utiliser "\n".join(list_of_lines).

123
DGH

Pourquoi est-il impossible d'utiliser une chaîne pour une nouvelle ligne dans write (), mais je peux l'utiliser dans writeelines ()?

L'idée est la suivante: si vous voulez écrire une seule chaîne, vous pouvez le faire avec write(). Si vous avez une séquence de chaînes, vous pouvez toutes les écrire en utilisant writelines().

write(arg) attend une chaîne en tant qu'argument et l'écrit dans le fichier. Si vous fournissez une liste de chaînes, cela déclenchera une exception (en passant, montrez-nous les erreurs!).

writelines(arg) attend un argument itérable (un objet itérable peut être un tuple, une liste, une chaîne ou un itérateur au sens le plus général). Chaque élément contenu dans l'itérateur est censé être une chaîne. Un tuple de chaînes est ce que vous avez fourni, donc les choses ont fonctionné.

La nature de la chaîne n’a pas d’importance pour les deux fonctions, c’est-à-dire qu’elles écrivent simplement dans le fichier ce que vous leur fournissez. La partie intéressante est que writelines() n'ajoute pas de caractères de nouvelle ligne, donc le nom de la méthode peut en réalité être assez déroutant. Il se comporte en réalité comme une méthode imaginaire appelée write_all_of_these_strings(sequence).

Ce qui suit est une manière idiomatique dans Python d'écrire une liste de chaînes dans un fichier tout en conservant chaque chaîne dans sa propre ligne:

lines = ['line1', 'line2']
with open('filename.txt', 'w') as f:
    f.write('\n'.join(lines))

Cela permet de fermer le fichier pour vous. La construction '\n'.join(lines) concatène (connecte) les chaînes de la liste lines et utilise le caractère '\ n' comme colle. C'est plus efficace que d'utiliser l'opérateur +.

Partant de la même séquence lines et aboutissant à la même sortie, mais en utilisant writelines():

lines = ['line1', 'line2']
with open('filename.txt', 'w') as f:
    f.writelines("%s\n" % l for l in lines)

Cela utilise une expression génératrice et crée dynamiquement des chaînes terminées par une nouvelle ligne. writelines() effectue une itération sur cette séquence de chaînes et écrit chaque élément.

Edit: Un autre point dont vous devriez être conscient:

write() et readlines() existaient avant l'introduction de writelines(). writelines() a été introduit plus tard en tant que contrepartie de readlines(), de sorte que l'on puisse facilement écrire le contenu du fichier qui vient d'être lu via readlines():

outfile.writelines(infile.readlines())

Vraiment, c’est la principale raison pour laquelle writelines a un nom aussi déroutant. De plus, aujourd'hui, nous ne voulons plus vraiment utiliser cette méthode. readlines() lit l'intégralité du fichier dans la mémoire de votre machine avant writelines() de commencer à écrire les données. Tout d'abord, cela peut faire perdre du temps. Pourquoi ne pas commencer à écrire des parties de données tout en lisant d’autres? Mais, le plus important, cette approche peut être très gourmande en mémoire. Dans un scénario extrême, où le fichier d'entrée est plus volumineux que la mémoire de votre ordinateur, cette approche ne fonctionnera même pas. La solution à ce problème consiste à utiliser uniquement des itérateurs. Un exemple de travail:

with open('inputfile') as infile:
    with open('outputfile') as outfile:
        for line in infile:
            outfile.write(line)

Ceci lit le fichier d’entrée ligne par ligne. Dès qu'une ligne est lue, cette ligne est écrite dans le fichier de sortie. Schématiquement, il n'y a toujours qu'une seule ligne en mémoire (par rapport à la totalité du contenu du fichier qui est en mémoire dans le cas de l'approche readlines/writelines).

108
Jan-Philip Gehrcke