No shell do Python 2.6:
>>> import sys
>>> print sys.getdefaultencoding()
ascii
>>> print u'\xe9'
é
>>>
Eu esperava ter alguma bobagem ou um erro após a declaração de impressão, pois o caractere "é" não faz parte do ASCII e não especifiquei uma codificação. Acho que não entendo o que significa ASCII como codificação padrão.
EDITAR
Mudei a edição para a seção Respostas e a aceitei como sugerido.
'\xe9'
em um terminal configurado para UTF-8 não será impressoé
. Ele imprimirá um caractere de substituição (geralmente um ponto de interrogação), pois\xe9
não é uma sequência UTF-8 válida (faltam dois bytes que deveriam ter seguido o byte inicial). Certamente não será interpretado como latino-1.\xe9
imprimir para imprimiré
.Respostas:
Graças aos fragmentos de várias respostas, acho que podemos explicar uma explicação.
Ao tentar imprimir uma cadeia de caracteres unicode, u '\ xe9', o Python tenta codificar implicitamente essa cadeia usando o esquema de codificação atualmente armazenado em sys.stdout.encoding. Na verdade, o Python pega essa configuração no ambiente em que foi iniciada. Se não conseguir encontrar uma codificação adequada do ambiente, só então reverterá para o padrão ASCII.
Por exemplo, eu uso um shell bash que codifica como padrão UTF-8. Se eu iniciar o Python, ele pega e usa essa configuração:
Vamos sair por um momento do shell Python e definir o ambiente do bash com alguma codificação falsa:
Em seguida, inicie o shell python novamente e verifique se ele realmente reverte para a codificação ASCII padrão.
Bingo!
Se você agora tentar gerar algum caractere unicode fora do ascii, deverá receber uma boa mensagem de erro
Vamos sair do Python e descartar o shell bash.
Vamos agora observar o que acontece depois que o Python produz strings. Para isso, primeiro iniciaremos um shell bash dentro de um terminal gráfico (eu uso o Gnome Terminal) e definiremos o terminal para decodificar a saída com a ISO-8859-1, também conhecida como latin-1 (os terminais gráficos geralmente têm uma opção para definir caracteres Codificação em um de seus menus suspensos). Observe que isso não altera a codificação do ambiente de shell real , apenas altera a maneira como o próprio terminal decodifica a saída fornecida, um pouco como um navegador da Web. Portanto, você pode alterar a codificação do terminal, independentemente do ambiente do shell. Vamos então iniciar o Python a partir do shell e verificar se sys.stdout.encoding está definido como a codificação do ambiente do shell (UTF-8 para mim):
(1) python gera uma string binária como está, o terminal a recebe e tenta combinar seu valor com o mapa de caracteres latin-1. Em latin-1, 0xe9 ou 233 produz o caractere "é" e é isso que o terminal exibe.
(2) o python tenta codificar implicitamente a cadeia Unicode com qualquer esquema atualmente definido em sys.stdout.encoding; nesse caso, é "UTF-8". Após a codificação UTF-8, a sequência binária resultante é '\ xc3 \ xa9' (consulte a explicação posterior). O terminal recebe o fluxo como tal e tenta decodificar 0xc3a9 usando latin-1, mas latin-1 vai de 0 a 255 e, portanto, apenas decodifica os fluxos de 1 byte por vez. 0xc3a9 tem 2 bytes, o decodificador latin-1, portanto, o interpreta como 0xc3 (195) e 0xa9 (169) e que gera 2 caracteres: Ã e ©.
(3) python codifica o ponto de código unicode u '\ xe9' (233) com o esquema latin-1. Acontece que o intervalo de pontos de código latin-1 é de 0 a 255 e aponta exatamente para o mesmo caractere que Unicode dentro desse intervalo. Portanto, os pontos de código Unicode nesse intervalo produzirão o mesmo valor quando codificados em latin-1. Portanto, u '\ xe9' (233) codificado em latin-1 também produzirá a cadeia binária '\ xe9'. O terminal recebe esse valor e tenta correspondê-lo no mapa de caracteres latin-1. Assim como no caso (1), produz "é" e é isso que é exibido.
Vamos agora alterar as configurações de codificação do terminal para UTF-8 no menu suspenso (como você alteraria as configurações de codificação do navegador da web). Não há necessidade de parar o Python ou reiniciar o shell. A codificação do terminal agora corresponde à do Python. Vamos tentar imprimir novamente:
(4) python gera uma string binária como está. O terminal tenta decodificar esse fluxo com UTF-8. Mas o UTF-8 não entende o valor 0xe9 (veja a explicação posterior) e, portanto, não pode convertê-lo em um ponto de código unicode. Nenhum ponto de código encontrado, nenhum caractere impresso.
(5) python tenta codificar implicitamente a cadeia Unicode com o que estiver em sys.stdout.encoding. Ainda "UTF-8". A sequência binária resultante é '\ xc3 \ xa9'. O terminal recebe o fluxo e tenta decodificar 0xc3a9 também usando UTF-8. Ele retorna o valor do código 0xe9 (233), que no mapa de caracteres Unicode aponta para o símbolo "é". O terminal exibe "é".
(6) python codifica string unicode com latin-1, produz uma string binária com o mesmo valor '\ xe9'. Novamente, para o terminal, isso é praticamente o mesmo do caso (4).
Conclusões: - Python gera strings não unicode como dados brutos, sem considerar sua codificação padrão. O terminal apenas os exibe se sua codificação atual corresponder aos dados. - Python gera seqüências de caracteres Unicode após codificá-las usando o esquema especificado em sys.stdout.encoding. - Python obtém essa configuração do ambiente do shell. - o terminal exibe a saída de acordo com suas próprias configurações de codificação. - a codificação do terminal é independente da do shell.
Mais detalhes sobre unicode, UTF-8 e latin-1:
Unicode é basicamente uma tabela de caracteres em que algumas chaves (pontos de código) foram convencionalmente atribuídas para apontar para alguns símbolos. Por exemplo, por convenção, foi decidido que a chave 0xe9 (233) é o valor que aponta para o símbolo 'é'. ASCII e Unicode usam os mesmos pontos de código de 0 a 127, assim como latin-1 e Unicode de 0 a 255. Ou seja, 0x41 aponta para 'A' em ASCII, latin-1 e Unicode, 0xc8 aponta para 'Ü' em latin-1 e Unicode, 0xe9 aponta para 'é' em latin-1 e Unicode.
Ao trabalhar com dispositivos eletrônicos, os pontos de código Unicode precisam de uma maneira eficiente de serem representados eletronicamente. É disso que tratam os esquemas de codificação. Existem vários esquemas de codificação Unicode (utf7, UTF-8, UTF-16, UTF-32). A abordagem de codificação mais intuitiva e direta seria simplesmente usar o valor de um ponto de código no mapa Unicode como valor para sua forma eletrônica, mas atualmente o Unicode possui mais de um milhão de pontos de código, o que significa que alguns deles exigem que sejam necessários 3 bytes. expressa. Para trabalhar eficientemente com texto, um mapeamento 1 para 1 seria bastante impraticável, pois exigiria que todos os pontos de código fossem armazenados exatamente na mesma quantidade de espaço, com um mínimo de 3 bytes por caractere, independentemente da necessidade real.
A maioria dos esquemas de codificação tem deficiências em relação ao requisito de espaço, os mais econômicos não cobrem todos os pontos de código unicode, por exemplo, o ascii cobre apenas os primeiros 128, enquanto o latin-1 cobre os primeiros 256. Outros que tentam ser mais abrangentes também acabam ser um desperdício, uma vez que exigem mais bytes do que o necessário, mesmo para caracteres "baratos" comuns. O UTF-16, por exemplo, usa no mínimo 2 bytes por caractere, incluindo aqueles no intervalo ascii ('B', que é 65, ainda requer 2 bytes de armazenamento no UTF-16). UTF-32 é ainda mais inútil, pois armazena todos os caracteres em 4 bytes.
O UTF-8 resolveu o dilema de maneira inteligente, com um esquema capaz de armazenar pontos de código com uma quantidade variável de espaços de bytes. Como parte de sua estratégia de codificação, o UTF-8 amarra pontos de código com bits de flag que indicam (presumivelmente para decodificadores) seus requisitos de espaço e seus limites.
Codificação UTF-8 de pontos de código unicode no intervalo ascii (0-127):
por exemplo, o ponto de código Unicode para 'B' é '0x42' ou 0100 0010 em binário (como dissemos, é o mesmo em ASCII). Após a codificação em UTF-8, torna-se:
Codificação UTF-8 de pontos de código Unicode acima de 127 (não ascii):
por exemplo, o ponto de código Unicode 'é' é 0xe9 (233).
Quando UTF-8 codifica esse valor, ele determina que o valor é maior que 127 e menor que 2048; portanto, deve ser codificado em 2 bytes:
O código 0xe9 Unicode aponta após a codificação UTF-8 se tornar 0xc3a9. Qual é exatamente como o terminal o recebe. Se seu terminal estiver configurado para decodificar strings usando latin-1 (uma das codificações herdadas não unicode), você verá à ©, porque acontece que 0xc3 em latin-1 aponta para à e 0xa9 para ©.
fonte
Quando caracteres Unicode são impressos em stdout,
sys.stdout.encoding
é usado. Presume-se que um caractere não Unicode esteja dentrosys.stdout.encoding
e é enviado apenas ao terminal. No meu sistema (Python 2):sys.getdefaultencoding()
é usado apenas quando o Python não tem outra opção.Observe que o Python 3.6 ou posterior ignora as codificações no Windows e usa APIs Unicode para gravar Unicode no terminal. Nenhum aviso UnicodeEncodeError e o caractere correto são exibidos se a fonte suportar. Mesmo que a fonte não a suporte, os caracteres ainda podem ser recortados e colados do terminal para um aplicativo com uma fonte de suporte e ela estará correta. Melhoria!
fonte
O Python REPL tenta captar qual codificação usar em seu ambiente. Se encontrar algo sadio, tudo funcionará. É quando não consegue descobrir o que está acontecendo que o problema ocorre.
fonte
TypeError: readonly attribute
no 2.7.2Você ter especificado uma codificação inserindo uma seqüência de caracteres Unicode explícito. Compare os resultados de não usar o
u
prefixo.No caso de
\xe9
então, o Python assume sua codificação padrão (Ascii), imprimindo ... algo em branco.fonte
Funciona para mim:
fonte
De acordo com as codificações e conversões de sequência padrão / implícitas do Python :
print
ingunicode
, éencode
d com<file>.encoding
.encoding
não está definido,unicode
é implicitamente convertido emstr
(já que o codec para isso ésys.getdefaultencoding()
, ou sejaascii
, qualquer caractere nacional causaria aUnicodeEncodeError
)encoding
é inferido do ambiente. É normalmente definido paratty
fluxos (a partir das configurações de localidade do terminal), mas provavelmente não será definido para tubosprint u'\xe9'
provavelmente terá êxito quando a saída for para um terminal e falhará se for redirecionado. Uma solução éencode()
a string com a codificação desejada antes deprint
ing.print
ingstr
, os bytes são enviados para o fluxo como estão. Os glifos mostrados pelo terminal dependerão de suas configurações de localidade.fonte