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.openpreferí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.openpreferível open?
Respostas:
Desde o Python 2.6, uma boa prática é usar io.open(), que também leva um encodingargumento, 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.
opene e codecs.open, especificamente, quando o último é preferível ao primeiro. Uma resposta que nem mesmo menciona codecs.opennã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.openmenos 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.openpois 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 opensubstituicodecs.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.opennão leva um parâmetro de codificação do que posso ver em python 2.7.5
io.openaceita encodinge newlineparâmetros e os interpreta como o Python 3 faz. Ao contrário codecs.open, um arquivo aberto com io.openaumentará TypeError: write() argument 1 must be unicode, not straté mesmo no Python 2.7 se você tentar escrever str( bytes) nele. Um arquivo aberto com codecs.opententará, 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.openpara 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.opennã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.openpermite 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 opennã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.openno 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.opene io.opentambé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.opene io.opendiferem em termos de sintaxe, eles retornam objetos do tipo diferente. Também codecs.opensempre 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.opene pode ser usado em seu lugar.
Nota:
codecs.openestá planejado para se tornar obsoleto e substituído porio.openapó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.openou codecs.open? 2. codecs.openainda 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 umencodingargumento.