Por que declarar unicode por string em python?

122

Ainda estou aprendendo python e tenho uma dúvida:

No python 2.6.x, normalmente declaro codificação no cabeçalho do arquivo como este (como no PEP 0263 )

# -*- coding: utf-8 -*-

Depois disso, minhas cordas são escritas como de costume:

a = "A normal string without declared Unicode"

Mas sempre que vejo um código de projeto python, a codificação não é declarada no cabeçalho. Em vez disso, é declarado em cada sequência como esta:

a = u"A string with declared Unicode"

Qual é a diferença? Qual é o objetivo disso? Eu sei que o Python 2.6.x define a codificação ASCII por padrão, mas pode ser substituída pela declaração do cabeçalho, então qual é o ponto da declaração por string?

Adendo: Parece que eu misturei codificação de arquivo com codificação de string. Obrigado por explicar :)

Oscar Carballal
fonte
6
# coding: utf8é bom o suficiente, não há necessidade de-*-
água-viva
1
@jellyfish Suponho que você quis digitar # coding: utf-8.
Samuel Harmer
Deveria ser #coding=utf-8. python.org/dev/peps/pep-0263
Guangtong Shen

Respostas:

167

Essas são duas coisas diferentes, como outros já mencionaram.

Ao especificar# -*- coding: utf-8 -*- , você está dizendo ao Python o arquivo de origem que você salvou utf-8. O padrão para o Python 2 é ASCII (para o Python 3 é utf-8). Isso afeta apenas como o intérprete lê os caracteres no arquivo.

Em geral, provavelmente não é a melhor ideia incorporar caracteres unicode altos em seu arquivo, independentemente da codificação; você pode usar escapes unicode de string, que funcionam em qualquer uma das codificações.


Quando você declara uma string com um una frente , como u'This is a string', ele diz ao compilador Python que a string é Unicode, não bytes. Isso é tratado principalmente de forma transparente pelo intérprete; a diferença mais óbvia é que agora você pode incorporar caracteres unicode na string (ou seja, u'\u2665'agora é legal). Você pode usar from __future__ import unicode_literalspara torná-lo o padrão.

Isso se aplica apenas ao Python 2; no Python 3, o padrão é Unicode e você precisa especificar um bna frente (como b'These are bytes', para declarar uma sequência de bytes).

Chris B.
fonte
Obrigada pelo esclarecimento! Vou definir isso como aceite uma vez que é a mais completa :)
Oscar Carballal
2
A codificação de origem padrão para Python 2 é ascii .
Mark Tolonen
27
Na verdade, é uma ótima idéia incorporar caracteres unicode altos em seu arquivo. Duvido que falantes de inglês não queiram ler escapes unicode em suas strings.
Mark Tolonen
@ Mark: Obrigado pela correção ASCII; Eu rapidamente vasculhei o PEP ( python.org/dev/peps/pep-0263 ) e ele fala sobre o Latin-1 no preâmbulo. Não acho que seja uma boa ideia incorporar caracteres unicode altos em seu arquivo na maioria dos casos. Certamente, se você estiver codificando muitas seqüências que não sejam do inglês no seu arquivo de origem, isso pode facilitar, mas geralmente você faz isso para exibição ao usuário, e provavelmente deve defini-las em um local separado de qualquer maneira. E um único editor de texto mal configurado pode corromper todos esses caracteres.
31410 Chris
4
concordou se você está programando um aplicativo personalizado, mas considere se você é um programador chinês ou francês. Não são apenas as cordas, mas os comentários também. É ótimo que o Python seja flexível com as codificações de origem. O Python 3 pode até ter caracteres não ASCII em nomes de variáveis.
Mark3: 10-13
23

Como já foi dito, # coding:especifica a codificação na qual o arquivo de origem é salvo. Aqui estão alguns exemplos para ilustrar isso:

Um arquivo salvo no disco como cp437 (codificação do meu console), mas nenhuma codificação declarada

b = 'über'
u = u'über'
print b,repr(b)
print u,repr(u)

Resultado:

  File "C:\ex.py", line 1
SyntaxError: Non-ASCII character '\x81' in file C:\ex.py on line 1, but no
encoding declared; see http://www.python.org/peps/pep-0263.html for details

Saída do arquivo com # coding: cp437adição:

über '\x81ber'
über u'\xfcber'

No começo, o Python não conhecia a codificação e reclamou do caractere não ASCII. Depois de conhecer a codificação, a sequência de bytes obteve os bytes que estavam no disco. Para a cadeia Unicode, o Python leu \ x81, sabia que no cp437 era um ü e o decodificou no ponto de código Unicode para ü, que é U + 00FC. Quando a sequência de bytes foi impressa, o Python enviou o valor hexadecimal 81ao console diretamente. Quando a string Unicode foi impressa, o Python detectou corretamente a codificação do console como cp437 e converteu Unicode ü no valor cp437 de ü .

Aqui está o que acontece com um arquivo declarado e salvo em UTF-8:

├╝ber '\xc3\xbcber'
über u'\xfcber'

No UTF-8, ü é codificado como bytes hexadecimais C3 BC, portanto a sequência de bytes contém esses bytes, mas a sequência Unicode é idêntica ao primeiro exemplo. O Python leu os dois bytes e decodificou-o corretamente. O Python imprimiu a sequência de bytes incorretamente, porque enviou os dois bytes UTF-8 que representam ü diretamente ao meu console do cp437.

Aqui, o arquivo é declarado cp437, mas salvo em UTF-8:

├╝ber '\xc3\xbcber'
├╝ber u'\u251c\u255dber'

A sequência de bytes ainda obteve os bytes no disco (bytes hexadecimais UTF-8 C3 BC), mas os interpretou como dois caracteres cp437 em vez de um único caractere codificado em UTF-8. Esses dois caracteres foram traduzidos para pontos de código Unicode e tudo é impresso incorretamente.

Mark Tolonen
fonte
10

Isso não define o formato da string; define o formato do arquivo. Mesmo com esse cabeçalho, "hello"é uma sequência de bytes, não uma sequência Unicode. Para torná-lo Unicode, você precisará usar em u"hello"qualquer lugar. O cabeçalho é apenas uma dica de qual formato usar ao ler o .pyarquivo.

icktoofay
fonte
Eu estava enganado então, pensei que eles eram os mesmos. Portanto, o uso de strings unicode é i18n?
Oscar Carballal
@ Oscar: Sim, na maior parte. Se você estava criando um site com o Django ou algo assim e precisou lidar com pessoas com caracteres não ASCII, esse é outro uso possível.
Icktoofay
7

A definição do cabeçalho é definir a codificação do próprio código, não as seqüências resultantes no tempo de execução.

colocar um caractere não-ascii como ۲ no script python sem a definição de cabeçalho utf-8 emitirá um aviso

erro

ebt
fonte
-1

Eu criei o seguinte módulo chamado unicoder para poder fazer a transformação em variáveis:

import sys
import os

def ustr(string):

    string = 'u"%s"'%string

    with open('_unicoder.py', 'w') as script:

        script.write('# -*- coding: utf-8 -*-\n')
        script.write('_ustr = %s'%string)

    import _unicoder
    value = _unicoder._ustr

    del _unicoder
    del sys.modules['_unicoder']

    os.system('del _unicoder.py')
    os.system('del _unicoder.pyc')

    return value

Em seu programa, você pode fazer o seguinte:

# -*- coding: utf-8 -*-

from unicoder import ustr

txt = 'Hello, Unicode World'
txt = ustr(txt)

print type(txt) # <type 'unicode'>
tecnobillo
fonte