Eu vi alguns scripts py que usam isso na parte superior do script. Em que casos se deve usá-lo?
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
Eu vi alguns scripts py que usam isso na parte superior do script. Em que casos se deve usá-lo?
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
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, a setdefaultencoding()
função é removida do sys
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:
sys.stdout
quando tiver uma None
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
, mas LC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)'
dá ANSI_X3.4-1968
(ou talvez algo mais)
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.
(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")
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)
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")
também tem o efeito colateral de parecer consertar sys.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 apenas PYTHONIOENCODING
a 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"
€
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/
def welcome_message(byte_string):
try:
return u"%s runs your business" % byte_string
except UnicodeError:
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 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
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 a setdefaultencoding
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.
#!/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 is None):
print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
exit(1)
então, usando o mesmo exemplo:
export PYTHONIOENCODING=UTF-8
./test.py > output.txt
vai funcionar
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:
(This is IPython 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]: import IPython.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.
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á.