Por que unicode () usa str () no meu objeto somente com nenhuma codificação dado?

StackOverflow https://stackoverflow.com/questions/106630

  •  01-07-2019
  •  | 
  •  

Pergunta

Gostaria de começar por criar uma variável string com alguns não-ascii utf-8 dados codificados nele:

>>> text = 'á'
>>> text
'\xc3\xa1'
>>> text.decode('utf-8')
u'\xe1'

Usando unicode() sobre ele gera erros ...

>>> unicode(text)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: 
                    ordinal not in range(128)

... mas se eu sei a codificação eu posso usá-lo como segundo parâmetro:

>>> unicode(text, 'utf-8')
u'\xe1'
>>> unicode(text, 'utf-8') == text.decode('utf-8')
True

Agora, se eu tiver uma classe que retorna este texto no método __str__():

>>> class ReturnsEncoded(object):
...     def __str__(self):
...         return text
... 
>>> r = ReturnsEncoded()
>>> str(r)
'\xc3\xa1'

unicode(r) parece usar str() sobre ele, uma vez que aumenta o mesmo erro que unicode(text) acima:

>>> unicode(r)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: 
                    ordinal not in range(128)

Até agora tudo está como planejado!

Mas, como ninguém jamais iria esperar, unicode(r, 'utf-8') não vai mesmo tentar:

>>> unicode(r, 'utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: coercing to Unicode: need string or buffer, ReturnsEncoded found

Por quê? Por que esse comportamento inconsistente? É um bug? se destina? Muito estranho.

Foi útil?

Solução

O comportamento parece confuso, mas intensional. Reproduzo aqui a totalidade da documentação unicode do Python Built-In documentação Funções (para a versão 2.5.2, enquanto escrevo isso):

Unicode ([objeto [, que codifica [, erros]]])

Voltar a versão seqüência de caracteres Unicode de objeto usando um dos seguintes modos:

Se a codificação e / ou erros são dadas, Unicode () irá descodificar o objecto que pode ser uma cadeia de caracteres de 8 bits, ou um buffer de caracteres usando o codec para a codificação. O parâmetro codificação é uma string dando o nome de uma codificação; Se a codificação não é conhecido, LookupError é levantada. tratamento de erros é feito de acordo com a erros; este define o tratamento de caracteres que sejam inválidos na codificação de entrada. Se os erros é 'estrita' (o padrão), um ValueError é gerado em erros, enquanto um valor de 'Ignorar' causa erros para ser ignorado, e um valor de 'Substituir' faz com que o caráter oficial de substituição Unicode, L + FFFD, para ser usado para substituir os caracteres de entrada, que não pode ser decodificado. Veja também a codecs módulo.

Se há parâmetros opcionais são dadas, unicode () irá imitar o comportamento de str (), excepto que ele retorna cadeias Unicode em vez de cordas de 8 bits. Mais precisamente, se o objeto é um Unicode string ou subclasse ele irá retornar essa seqüência Unicode sem qualquer decodificação adicional aplicado.

Para objetos que proporcionam uma __unicode __ () método, ele irá chamar este método sem argumentos para criar uma seqüência de caracteres Unicode. Para todos os outros objetos, a versão seqüência de 8-bit ou representação é solicitado e, em seguida, convertido em uma seqüência de caracteres Unicode usando o codec para o padrão de codificação no modo 'rigorosa'.

Novo na versão 2.0. Alterado na versão 2.2: Suporte para __unicode __ () acrescentou.

Assim, quando você chamar unicode(r, 'utf-8'), requer uma seqüência de 8 bits ou um buffer de caracteres como o primeiro argumento, por isso coage o seu objeto usando o método __str__(), e tentativas de decodificação que usando o codec utf-8. Sem a utf-8, a aparência de função unicode() para um para um método __unicode__() em seu objeto, e não encontrá-lo, chama o método __str__(), como você sugeriu, tentando usar o codec padrão para converter para unicode.

Outras dicas

unicode não acho que a codificação do seu texto. Se o objeto pode imprimir-se como unicode, definir o método __unicode__() que retorna uma seqüência de caracteres Unicode.


O segredo é que unicode(r) não está realmente chamando __str__() si. Em vez disso, ele está à procura de um método __unicode__(). A implementação padrão de __unicode__() chamará __str__() e depois tentar decodificá-lo usando o charset ascii. Quando você passar a codificação, unicode() espera que o primeiro objeto a ser algo que pode ser decodificado -. Ou seja, uma instância de basestring


O comportamento é estranho, porque ele tenta decodificar como ascii se eu não passar 'utf-8'. Mas se eu passar 'utf-8' dá um erro diferente ...

Isso porque quando você especificar "utf-8", ele trata o primeiro parâmetro como uma string-como objeto a ser decodificado. Sem ela, ele trata o parâmetro como um objeto a ser coagidos a unicode.

Eu não entendo a confusão. Se você sabe que atributo text do objeto será sempre UTF-8 codificado, basta definir __unicode__() e então tudo vai funcionar bem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top