Python - write () versus writelines () e seqüências de caracteres concatenadas


124

Então, eu estou aprendendo Python. Estou passando pelas lições e tive um problema em que tive que condensar muitos target.write()em um único write(), enquanto tinha uma "\n"variável de entrada entre cada usuário (o objeto de write()).

Eu vim com:

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

Se eu tentar fazer:

textdoc.write(lines)

Eu recebo um erro. Mas se eu digitar:

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

Então funciona bem. Por que não consigo usar uma string para uma nova linha, write()mas posso usá-la writelines()?

Python 2.7 Quando pesquisei no google a maioria dos recursos que encontrei, estava na minha cabeça, ainda sou um leigo.


linesnão é uma string no seu exemplo. É uma tupla composta por seis cordas.
Bachsau 26/07/19

Respostas:


147
  • writelines espera um iterável de strings
  • write espera uma única sequência.

line1 + "\n" + line2mescla essas strings em uma única string antes de passá-las para write.

Observe que, se você tiver muitas linhas, poderá usar "\n".join(list_of_lines).


50
Mais especificamente, writelinesespera um iterável. Você pode usar uma lista, uma tupla ou um gerador.
Mark Ransom

Obrigado pela resposta, senhor. Estou assumindo pelo nome (list_of_lines) que devo fazer uma lista de strings e passar para .join (list)?
AbeLinkon

9
Por que você deve usar em writevez de writelinesse tiver muitas linhas? Writelines pode ter um desempenho melhor, pois não precisa criar uma sequência concatenada temporária, apenas repetindo as linhas.
Bouke

@ hBy2Py: exatamente o contrário: stackoverflow.com/a/6165711/281545
Mr_and_Mrs_D

1
A única corda também é um iterável em Python
natbusa

122

Por que não consigo usar uma string para uma nova linha em write (), mas posso usá-la em writelines ()?

A idéia é a seguinte: se você deseja escrever uma única string, pode fazê-lo write(). Se você tiver uma sequência de strings, poderá escrever todas elas usando writelines().

write(arg)espera uma string como argumento e a grava no arquivo Se você fornecer uma lista de strings, isso gerará uma exceção (a propósito, mostre erros para nós!).

writelines(arg)espera um argumento iterável como (um objeto iterável pode ser uma tupla, uma lista, uma string ou um iterador no sentido mais geral). Espera-se que cada item contido no iterador seja uma sequência. Uma tupla de strings é o que você forneceu, para que as coisas funcionassem.

A natureza das strings não importa para as duas funções, ou seja, elas apenas gravam no arquivo o que você fornecer. A parte interessante é que writelines()não adiciona caracteres de nova linha por conta própria, portanto o nome do método pode ser bastante confuso. Na verdade, ele se comporta como um método imaginário chamado write_all_of_these_strings(sequence).

A seguir, é uma maneira idiomática no Python para escrever uma lista de strings em um arquivo, mantendo cada string em sua própria linha:

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

Isso cuida do fechamento do arquivo para você. A construção '\n'.join(lines)concatena (conecta) as seqüências de caracteres na lista linese usa o caractere '\ n' como cola. É mais eficiente do que usar o +operador.

Começando na mesma linessequência, terminando com a mesma saída, mas usando writelines():

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

Isso faz uso de uma expressão de gerador e cria dinamicamente seqüências terminadas em nova linha. writelines()itera sobre essa sequência de strings e grava todos os itens.

Edit: Outro ponto que você deve estar ciente de:

write()e readlines()existia antes de writelines()ser introduzido. writelines()foi introduzido mais tarde como uma contrapartida de readlines(), para que se pudesse escrever facilmente o conteúdo do arquivo que acabou de ser lido através de readlines():

outfile.writelines(infile.readlines())

Realmente, essa é a principal razão pela qual writelinesesse nome é confuso. Além disso, hoje, realmente não queremos mais usar esse método. readlines()lê o arquivo inteiro na memória da sua máquina antes de writelines()começar a gravar os dados. Primeiro de tudo, isso pode perder tempo. Por que não começar a escrever partes dos dados enquanto lê outras partes? Mas, o mais importante, essa abordagem pode consumir muita memória. Em um cenário extremo, onde o arquivo de entrada é maior que a memória da sua máquina, essa abordagem nem funciona. A solução para esse problema é usar apenas iteradores. Um exemplo de trabalho:

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

Isso lê o arquivo de entrada linha por linha. Assim que uma linha é lida, essa linha é gravada no arquivo de saída. Esquematicamente falado, sempre há apenas uma única linha na memória (em comparação com todo o conteúdo do arquivo na memória, no caso da abordagem de linhas de leitura / linhas de escrita).


5
@AbeLinkon: Eu não apoiaria esta conclusão. write()e writelines()são basicamente equivalentes e seu uso também é uma questão de gosto pessoal. No entanto, é importante observar que, para uma lista extremamente longa de strings (chamada lines), é menos eficiente escrever do f.write('\n'.join(lines))que for l in line: f.write('%s\n' % l). No primeiro caso, uma sequência inteiramente nova e muito longa é criada na memória antes de gravá-la. No segundo caso, os dados são escritos por partes.
Dr. Jan-Philip Gehrcke

3
f.write ('\ n'.join (linhas)) não adicionou o último nl quando o executei.
Jiminion 26/07/2013

5
Claro que você não faria, outf.writelines(inf.readlines())mas sim outf.writelines(inf). A função que não queremos mais usar readlines()não é writelines().
moooeeeep

2
@moooeeeep: enquanto nada está errado com a funcionalidade / implementação de writelines(), sua semântica é, como explicado, menos que o ideal. É por isso que nunca o usei. E eu nunca senti falta disso.
Dr. Jan-Philip Gehrcke

2
@AbeLinkon - talvez você deve considerar a aceitar esta resposta, é claramente melhor do que aquele que inicialmente aceitou
Peter M. - significa Monica

-4

se você quiser salvar e carregar uma lista, tente Pickle

Economia de picles:

with open("yourFile","wb")as file:
 pickle.dump(YourList,file)

e carregamento:

with open("yourFile","rb")as file:
 YourList=pickle.load(file)

-5

Na verdade, acho que o problema é que suas "linhas" variáveis ​​são ruins. Você definiu linhas como uma tupla, mas acredito que write () requer uma string. Tudo o que você precisa alterar são suas vírgulas em vantagens (+).

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

Deveria trabalhar.


-5

Exercício 16 do livro de Zed Shaw? Você pode usar caracteres de escape da seguinte maneira:

paragraph1 = "%s \n %s \n %s \n" % (line1, line2, line3)
target.write(paragraph1)
target.close()

Solução muito fraca. Se você queria para concatenar várias linhas desta maneira, você deve fazê-lo como este: " \n ".join((line1, line2, line3)).
Bachsau
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.