Existem duas maneiras de abrir um arquivo de texto em Python:
f = open(filename)
E
import codecs
f = codecs.open(filename, encoding="utf-8")
Quando é codecs.open
preferível open
?
Existem duas maneiras de abrir um arquivo de texto em Python:
f = open(filename)
E
import codecs
f = codecs.open(filename, encoding="utf-8")
Quando é codecs.open
preferível open
?
Respostas:
Desde o Python 2.6, uma boa prática é usar io.open()
, que também leva um encoding
argumento, como o now obsolete codecs.open()
. No Python 3, io.open
é um alias para o open()
integrado. Portanto, io.open()
funciona no Python 2.6 e em todas as versões posteriores, incluindo Python 3.4. Veja os documentos: http://docs.python.org/3.4/library/io.html
Agora, para a pergunta original: ao ler texto (incluindo "texto simples", HTML, XML e JSON) em Python 2, você deve sempre usar io.open()
com uma codificação explícita ou open()
com uma codificação explícita em Python 3. Isso significa que você acertou decodificar Unicode ou obter um erro logo de cara, tornando-o muito mais fácil de depurar.
O "texto simples" em ASCII puro é um mito do passado distante. O texto em inglês apropriado usa aspas curvas, travessões, marcadores, € (sinais de euro) e até mesmo diérese (¨). Não seja ingênuo! (E não vamos esquecer o padrão de design da fachada!)
Como o ASCII puro não é uma opção real, open()
sem uma codificação explícita só é útil para ler arquivos binários .
io.open()
para texto e open()
apenas para binário. A implicação é que codecs.open()
não é de todo preferido.
open
e e codecs.open
, especificamente, quando o último é preferível ao primeiro. Uma resposta que nem mesmo menciona codecs.open
não pode responder a essa pergunta.
codecs.open()
era correto usar), então não há uma resposta "correta" sobre quando usá-lo. A resposta é usar em seu io.open()
lugar. É como se eu perguntasse "quando devo usar uma chave inglesa para cravar um prego na parede?". A resposta certa é "use um martelo".
Pessoalmente, eu sempre uso, a codecs.open
menos que haja uma necessidade claramente identificada de uso open
**. A razão é que muitas vezes eu fui mordido por uma entrada de utf-8 furtivamente em meus programas. "Oh, eu só sei que sempre será ascii" tende a ser uma suposição que é quebrada com frequência.
Presumir 'utf-8' como a codificação padrão tende a ser uma escolha padrão mais segura em minha experiência, já que ASCII pode ser tratado como UTF-8, mas o inverso não é verdade. E, nos casos em que realmente sei que a entrada é ASCII, ainda acredito, codecs.open
pois acredito firmemente que "explícito é melhor do que implícito" .
** - no Python 2.x, pois o comentário sobre a pergunta afirma no Python 3 open
substituicodecs.open
open
às vezes consegue lidar muito bem com caracteres não latinos codificados em UTF-8 do conjunto Unicode, e às vezes falha miseravelmente ...
io.open
não leva um parâmetro de codificação do que posso ver em python 2.7.5
io.open
aceita encoding
e newline
parâmetros e os interpreta como o Python 3 faz. Ao contrário codecs.open
, um arquivo aberto com io.open
aumentará TypeError: write() argument 1 must be unicode, not str
até mesmo no Python 2.7 se você tentar escrever str
( bytes
) nele. Um arquivo aberto com codecs.open
tentará, em vez disso unicode
, a conversão implícita para , geralmente levando a arquivos confusos UnicodeDecodeError
.
No Python 2, existem strings Unicode e bytestrings. Se você apenas usar bytestrings, poderá ler / gravar em um arquivo aberto com open()
muito bem. Afinal, as strings são apenas bytes.
O problema surge quando, digamos, você tem uma string Unicode e faz o seguinte:
>>> example = u'Μου αρέσει Ελληνικά'
>>> open('sample.txt', 'w').write(example)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)
Então aqui obviamente você codifica explicitamente sua string Unicode em utf-8 ou usa codecs.open
para fazer isso de forma transparente.
Se você sempre usa bytestrings, não há problemas:
>>> example = 'Μου αρέσει Ελληνικά'
>>> open('sample.txt', 'w').write(example)
>>>
É mais complicado do que isso porque quando você concatena uma string Unicode e uma string de bytes com o +
operador, você obtém uma string Unicode. Fácil de ser mordido por aquele.
Também codecs.open
não gosta de bytes com caracteres não ASCII sendo passados em:
codecs.open('test', 'w', encoding='utf-8').write('Μου αρέσει')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/codecs.py", line 691, in write
return self.writer.write(data)
File "/usr/lib/python2.7/codecs.py", line 351, in write
data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xce in position 0: ordinal not in range(128)
O conselho sobre strings para entrada / saída é normalmente "converta para Unicode o mais cedo possível e de volta para bytestrings o mais tarde possível". Usar codecs.open
permite que você faça o último com muita facilidade.
Apenas tome cuidado para não fornecer strings Unicode e não bytes que possam conter caracteres não ASCII.
u''
no primeiro exemplo. Isso significa que criei uma string Unicode, não uma bytestring. Essa é a diferença entre os dois exemplos. No segundo exemplo, estou criando um bytestring e escrever um deles em um arquivo está ótimo. Uma string Unicode não funciona se você estiver usando caracteres fora de ASCII.
codecs.open
, suponho, é apenas um resquício da Python 2
época em que o open embutido tinha uma interface muito mais simples e menos recursos. No Python 2, embutido open
não aceita um argumento de codificação, então se você quiser usar algo diferente do modo binário ou a codificação padrão, codecs.open deveria ser usado.
Em Python 2.6
, o módulo io veio em ajuda para tornar as coisas um pouco mais simples. De acordo com a documentação oficial
New in version 2.6.
The io module provides the Python interfaces to stream handling.
Under Python 2.x, this is proposed as an alternative to the
built-in file object, but in Python 3.x it is the default
interface to access files and streams.
Dito isso, o único uso que posso pensar codecs.open
no cenário atual é para a compatibilidade com versões anteriores. Em todos os outros cenários (a menos que você esteja usando Python <2.6), é preferível usar io.open
. Também em Python 3.x
io.open
é o mesmo quebuilt-in open
Nota:
Há uma diferença sintática entre codecs.open
e io.open
também.
codecs.open
:
open(filename, mode='rb', encoding=None, errors='strict', buffering=1)
io.open
:
open(file, mode='r', buffering=-1, encoding=None,
errors=None, newline=None, closefd=True, opener=None)
codecs.open
e io.open
diferem em termos de sintaxe, eles retornam objetos do tipo diferente. Também codecs.open
sempre funciona com arquivos em modo binário.
Quando você quiser carregar um arquivo binário, use
f = io.open(filename, 'b')
.
Para abrir um arquivo de texto, use sempre f = io.open(filename, encoding='utf-8')
com codificação explícita.
No entanto, em python 3open
faz a mesma coisa io.open
e pode ser usado em seu lugar.
Nota:
codecs.open
está planejado para se tornar obsoleto e substituído porio.open
após sua introdução no python 2.6 . Eu só o usaria se o código precisar ser compatível com versões anteriores do python. Para mais informações sobre codecs e unicode em python, veja o Unicode HOWTO .
io.open
ou codecs.open
? 2. codecs.open
ainda não está obsoleto, leia a discussão na página que você vinculou.
Quando você está trabalhando com arquivos de texto e deseja codificação e decodificação transparentes em objetos Unicode.
Eu estava em uma situação de abrir um arquivo .asm e processar o arquivo.
#https://docs.python.org/3/library/codecs.html#codecs.ignore_errors
#https://docs.python.org/3/library/codecs.html#codecs.Codec.encode
with codecs.open(file, encoding='cp1252', errors ='replace') as file:
Sem muita dificuldade consigo ler todo o arquivo, alguma sugestão?
codecs.open()
está obsoleto no 3.x, poisopen()
ganha umencoding
argumento.