Como isso não é uma duplicata exata dos perigos de sys.setdefaultencoding ('utf-8') ? Embora essa pergunta (2010) anteceda essa (2015)? Mas essa pergunta também tem boas respostas. O que fazer? Além disso, para ficar claro, essa pergunta só faz sentido no Python 2 e não 3, mas isso não é marcado ou mencionado em nenhum lugar.
Conforme a documentação: Isso permite alternar do ASCII padrão para outras codificações, como UTF-8, que o tempo de execução do Python usará sempre que for necessário decodificar um buffer de cadeia para unicode.
Esta função está disponível apenas no momento da inicialização do Python, quando o Python verifica o ambiente. Ele deve ser chamado em um módulo de todo o sistema sitecustomize.py. Após a avaliação deste módulo, a setdefaultencoding()função é removida do sysmódulo.
A única maneira de realmente usá-lo é com um hack de recarga que traz o atributo de volta.
Além disso, o uso de sys.setdefaultencoding()sempre foi desencorajado e tornou-se um não operacional no py3k. A codificação do py3k é conectada por fio a "utf-8" e sua alteração gera um erro.
Gostaria de acrescentar que a codificação padrão também é usada para codificação (ao escrever para sys.stdoutquando tiver uma Nonecodificação, como ao redirecionar a saída de um programa Python).
Eric O Lebigot
14
+1 para "o uso de sys.setdefaultencoding()sempre foi desencorajado"
JFS
7
'hard-wired to utf-8' não é verdade, não é hardwired e nem sempre é UTF-8. LC_ALL=en_US.UTF-8 python3 -c 'import sys; print(sys.stdout.encoding)'dá UTF-8, mas LC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)'dá ANSI_X3.4-1968(ou talvez algo mais)
Tino
7
@Tino, a codificação do console é separada da codificação padrão.
Alastair McCormack
59
tl; dr
A resposta é NUNCA ! (a menos que você realmente saiba o que está fazendo)
9/10 vezes a solução pode ser resolvida com um entendimento adequado de codificação / decodificação.
1/10 pessoas têm um local ou ambiente definido incorretamente e precisam definir:
PYTHONIOENCODING="UTF-8"
em seu ambiente para corrigir problemas de impressão do console.
O que isso faz?
sys.setdefaultencoding("utf-8")(marcado para evitar reutilização) altera a codificação / decodificação padrão usada sempre que o Python 2.x precisar converter um Unicode () em um str () (e vice-versa) e a codificação não for fornecida. Ou seja:
str(u"\u20AC")
unicode("€")"{}".format(u"\u20AC")
No Python 2.x, a codificação padrão é definida como ASCII e os exemplos acima falharão com:
UnicodeDecodeError:'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)
(Meu console está configurado como UTF-8, portanto "€" = '\xe2\x82\xac', exceção \xe2)
ou
UnicodeEncodeError:'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
sys.setdefaultencoding("utf-8")permitirá que eles funcionem para mim , mas não necessariamente funcionará para pessoas que não usam UTF-8. O padrão do ASCII garante que as suposições de codificação não sejam inseridas no código
Console
sys.setdefaultencoding("utf-8")também tem o efeito colateral de parecer consertar sys.stdout.encoding, usado ao imprimir caracteres no console. O Python usa a localidade do usuário (Linux / OS X / Un * x) ou a página de código (Windows) para definir isso. Ocasionalmente, a localidade do usuário é interrompida e requer apenas PYTHONIOENCODINGa correção da codificação do console .
Exemplo:
$ export LANG=en_GB.gibberish
$ python
>>> import sys
>>> sys.stdout.encoding
'ANSI_X3.4-1968'
>>> print u"\u20AC"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
>>> exit()
$ PYTHONIOENCODING=UTF-8 python
>>> import sys
>>> sys.stdout.encoding
'UTF-8'
>>> print u"\u20AC"
€
O que há de tão ruim com sys.setdefaultencoding ("utf-8") ?
As pessoas desenvolvem o Python 2.x há 16 anos, entendendo que a codificação padrão é ASCII. UnicodeErrorOs métodos de tratamento de exceção foram gravados para manipular conversões de seqüência de caracteres em Unicode em seqüências que contêm não ASCII.
def welcome_message(byte_string):try:return u"%s runs your business"% byte_string
exceptUnicodeError:return u"%s runs your business"% unicode(byte_string,
encoding=detect_encoding(byte_string))print(welcome_message(u"Angstrom (Å®)".encode("latin-1"))
Antes de definir a codificação padrão, esse código não seria capaz de decodificar o "Å" na codificação ascii e, em seguida, entraria no manipulador de exceções para adivinhar a codificação e transformá-la adequadamente em unicode. Impressão: Angstrom (Å®) administra sua empresa. Depois de definir a codificação padrão como utf-8, o código descobrirá que o byte_string pode ser interpretado como utf-8 e, portanto, manipulará os dados e retornará isso: Angstrom (Ů) administra seus negócios.
Alterar o que deveria ser uma constante terá efeitos dramáticos nos módulos dos quais você depende. É melhor corrigir os dados que entram e saem do seu código.
Embora haja surpresas sys.setdefaultencoding("utf-8"), é bom fazer o código se comportar mais como o Python 3. É 2017 agora. Mesmo quando você escreveu a resposta em 2015, acho que já era melhor olhar para a frente do que para trás. Na verdade, era a solução mais simples para mim, quando descobri que meu código se comporta de maneira diferente no Python 2, dependendo se a saída é redirecionada (problema muito desagradável para o Python 2). Escusado será dizer que já o tenho # coding: utf-8e não preciso de soluções alternativas para o Python 3 (na verdade, tenho que mascarar a setdefaultencodingverificação de versão usando).
Yongwei Wu
Isso é ótimo e funciona para você, mas sys.setdefaultencoding("utf-8")não torna seu código Py 2.x compatível com o Python 3. Nem corrige módulos externos que assumem que a codificação padrão é ASCII. Tornar seu código compatível com Python 3 é muito simples e não requer esse truque desagradável. Por exemplo, por que isso causa problemas muito reais, veja minha experiência com a Amazon mexendo com essa suposição: stackoverflow.com/questions/39465220/…
Alastair McCormack:
1
@AlastairMcCormack you rock, Meu site tem sido há meses e não conseguia descobrir o que fazer. Por fim, PYTHONIOENCODING="UTF-8"ajudei meu ambiente Python2.7 Django-1.11. Obrigado.
sam
Eu sei que você copiou o exemplo, mas posso encontrar o pacote detect_encoding.
dlamblin
@ dlamblin O exemplo de código é para provar a citação e não deve ser usado em seu código. Imagine que esse detect_encodingé um método que pode detectar a codificação de uma string com base em dicas de idioma.
Alastair McCormack
18
#!/usr/bin/env python#-*- coding: utf-8 -*-
u = u'moçambique'print u.encode("utf-8")print u
chmod +x test.py
./test.py
moçambique
moçambique
./test.py > output.txt
Traceback(most recent call last):File"./test.py", line 5,in<module>print u
UnicodeEncodeError:'ascii' codec can't encode character
u'\xe7' in position 2: ordinal not in range(128)
no shell funciona, enviando para sdtout não, então essa é uma solução alternativa, para gravar em stdout.
Fiz outra abordagem, que não será executada se sys.stdout.encoding não estiver definida ou, em outras palavras, precisar exportar PYTHONIOENCODING = UTF-8 primeiro para gravar no stdout.
import sys
if(sys.stdout.encoding isNone):print>> sys.stderr,"please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
exit(1)
Isso não responde à pergunta conforme solicitado. Antes, alguns pensamentos tangenciais sobre o assunto.
precisa saber é o seguinte
3
O primeiro perigo está reload(sys).
Quando você recarrega um módulo, na verdade você obtém duas cópias do módulo em seu tempo de execução. O módulo antigo é um objeto Python como todo o resto e permanece vivo enquanto houver referências a ele. Portanto, metade dos objetos estará apontando para o módulo antigo e metade para o novo. Quando você faz alguma alteração, nunca a verá quando algum objeto aleatório não vê a alteração:
(ThisisIPython shell)In[1]:import sys
In[2]: sys.stdout
Out[2]:<colorama.ansitowin32.StreamWrapper at 0x3a2aac8>In[3]: reload(sys)<module 'sys'(built-in)>In[4]: sys.stdout
Out[4]:<open file '<stdout>', mode 'w' at 0x00000000022E20C0>In[11]:importIPython.terminal
In[14]:IPython.terminal.interactiveshell.sys.stdout
Out[14]:<colorama.ansitowin32.StreamWrapper at 0x3a9aac8>
Agora, sys.setdefaultencoding()adequado
Tudo o que afeta é a conversão implícitastr<->unicode . Agora, utf-8é a codificação mais segura do planeta (compatível com versões anteriores com ASCII e tudo mais), a conversão agora "simplesmente funciona", o que poderia dar errado?
Bem, qualquer coisa. E esse é o perigo.
Pode haver algum código que depende da UnicodeErrorativação para entrada não ASCII ou faz a transcodificação com um manipulador de erros, que agora produz um resultado inesperado. E como todo o código é testado com a configuração padrão, você está estritamente no território "não suportado" aqui e ninguém garante a você como o código deles se comportará.
Novamente, o pior é que você nunca saberá isso porque a conversão está implícita - você realmente não sabe quando e onde isso acontece. (Python Zen, koan 2 ahoy!) Você nunca saberá por que (e se) seu código funciona em um sistema e quebra em outro. (Ou melhor ainda, funciona no IDE e quebra no console.)
Respostas:
Conforme a documentação: Isso permite alternar do ASCII padrão para outras codificações, como UTF-8, que o tempo de execução do Python usará sempre que for necessário decodificar um buffer de cadeia para unicode.
Esta função está disponível apenas no momento da inicialização do Python, quando o Python verifica o ambiente. Ele deve ser chamado em um módulo de todo o sistema
sitecustomize.py
. Após a avaliação deste módulo, asetdefaultencoding()
função é removida dosys
módulo.A única maneira de realmente usá-lo é com um hack de recarga que traz o atributo de volta.
Além disso, o uso de
sys.setdefaultencoding()
sempre foi desencorajado e tornou-se um não operacional no py3k. A codificação do py3k é conectada por fio a "utf-8" e sua alteração gera um erro.Sugiro algumas dicas para leitura:
fonte
sys.stdout
quando tiver umaNone
codificação, como ao redirecionar a saída de um programa Python).sys.setdefaultencoding()
sempre foi desencorajado"UTF-8
.LC_ALL=en_US.UTF-8 python3 -c 'import sys; print(sys.stdout.encoding)'
dáUTF-8
, masLC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)'
dáANSI_X3.4-1968
(ou talvez algo mais)tl; dr
A resposta é NUNCA ! (a menos que você realmente saiba o que está fazendo)
9/10 vezes a solução pode ser resolvida com um entendimento adequado de codificação / decodificação.
1/10 pessoas têm um local ou ambiente definido incorretamente e precisam definir:
em seu ambiente para corrigir problemas de impressão do console.
O que isso faz?
(marcado para evitar reutilização) altera a codificação / decodificação padrão usada sempre que o Python 2.x precisar converter um Unicode () em um str () (e vice-versa) e a codificação não for fornecida. Ou seja:sys.setdefaultencoding("utf-8")
No Python 2.x, a codificação padrão é definida como ASCII e os exemplos acima falharão com:
(Meu console está configurado como UTF-8, portanto
"€" = '\xe2\x82\xac'
, exceção\xe2
)ou
permitirá que eles funcionem para mim , mas não necessariamente funcionará para pessoas que não usam UTF-8. O padrão do ASCII garante que as suposições de codificação não sejam inseridas no códigosys.setdefaultencoding("utf-8")
Console
também tem o efeito colateral de parecer consertarsys.setdefaultencoding("utf-8")
sys.stdout.encoding
, usado ao imprimir caracteres no console. O Python usa a localidade do usuário (Linux / OS X / Un * x) ou a página de código (Windows) para definir isso. Ocasionalmente, a localidade do usuário é interrompida e requer apenasPYTHONIOENCODING
a correção da codificação do console .Exemplo:
O que há de tão ruim com
sys.setdefaultencoding ("utf-8")?As pessoas desenvolvem o Python 2.x há 16 anos, entendendo que a codificação padrão é ASCII.
UnicodeError
Os métodos de tratamento de exceção foram gravados para manipular conversões de seqüência de caracteres em Unicode em seqüências que contêm não ASCII.De https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/
Alterar o que deveria ser uma constante terá efeitos dramáticos nos módulos dos quais você depende. É melhor corrigir os dados que entram e saem do seu código.
Problema de exemplo
Embora a configuração da codificação padrão para UTF-8 não seja a causa raiz no exemplo a seguir, mostra como os problemas são mascarados e como, quando a codificação de entrada é alterada, o código é quebrado de maneira não óbvia: UnicodeDecodeError: o codec 'utf8' pode decodifique o byte 0x80 na posição 3131: byte inicial inválido
fonte
sys.setdefaultencoding("utf-8")
, é bom fazer o código se comportar mais como o Python 3. É 2017 agora. Mesmo quando você escreveu a resposta em 2015, acho que já era melhor olhar para a frente do que para trás. Na verdade, era a solução mais simples para mim, quando descobri que meu código se comporta de maneira diferente no Python 2, dependendo se a saída é redirecionada (problema muito desagradável para o Python 2). Escusado será dizer que já o tenho# coding: utf-8
e não preciso de soluções alternativas para o Python 3 (na verdade, tenho que mascarar asetdefaultencoding
verificação de versão usando).sys.setdefaultencoding("utf-8")
não torna seu código Py 2.x compatível com o Python 3. Nem corrige módulos externos que assumem que a codificação padrão é ASCII. Tornar seu código compatível com Python 3 é muito simples e não requer esse truque desagradável. Por exemplo, por que isso causa problemas muito reais, veja minha experiência com a Amazon mexendo com essa suposição: stackoverflow.com/questions/39465220/…PYTHONIOENCODING="UTF-8"
ajudei meu ambiente Python2.7 Django-1.11. Obrigado.detect_encoding
.detect_encoding
é um método que pode detectar a codificação de uma string com base em dicas de idioma.no shell funciona, enviando para sdtout não, então essa é uma solução alternativa, para gravar em stdout.
Fiz outra abordagem, que não será executada se sys.stdout.encoding não estiver definida ou, em outras palavras, precisar exportar PYTHONIOENCODING = UTF-8 primeiro para gravar no stdout.
então, usando o mesmo exemplo:
vai funcionar
fonte
O primeiro perigo está
reload(sys)
.Quando você recarrega um módulo, na verdade você obtém duas cópias do módulo em seu tempo de execução. O módulo antigo é um objeto Python como todo o resto e permanece vivo enquanto houver referências a ele. Portanto, metade dos objetos estará apontando para o módulo antigo e metade para o novo. Quando você faz alguma alteração, nunca a verá quando algum objeto aleatório não vê a alteração:
Agora,
sys.setdefaultencoding()
adequadoTudo o que afeta é a conversão implícita
str<->unicode
. Agora,utf-8
é a codificação mais segura do planeta (compatível com versões anteriores com ASCII e tudo mais), a conversão agora "simplesmente funciona", o que poderia dar errado?Bem, qualquer coisa. E esse é o perigo.
UnicodeError
ativação para entrada não ASCII ou faz a transcodificação com um manipulador de erros, que agora produz um resultado inesperado. E como todo o código é testado com a configuração padrão, você está estritamente no território "não suportado" aqui e ninguém garante a você como o código deles se comportará.fonte