Perché dichiarare Unicode per stringa in Python?


122

Sto ancora imparando Python e ho un dubbio:

In python 2.6.x di solito dichiaro la codifica nell'intestazione del file in questo modo (come in PEP 0263 )

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

Dopodiché, le mie stringhe vengono scritte come al solito:

a = "A normal string without declared Unicode"

Ma ogni volta che vedo il codice di un progetto Python, la codifica non è dichiarata nell'intestazione. Invece, è dichiarato ad ogni stringa in questo modo:

a = u"A string with declared Unicode"

Qual è la differenza? Qual è lo scopo di questo? So che Python 2.6.x imposta la codifica ASCII per impostazione predefinita, ma può essere sovrascritto dalla dichiarazione dell'intestazione, quindi qual è lo scopo della dichiarazione per stringa?

Addendum: Sembra che io abbia confuso la codifica dei file con la codifica delle stringhe. Grazie per averlo spiegato :)


6
# coding: utf8è abbastanza buono, non -*-
medusa

1
@jellyfish Presumo che volessi digitare # coding: utf-8.
Samuel Harmer

Dovrebbe essere #coding=utf-8. python.org/dev/peps/pep-0263
Guangtong Shen

Risposte:


167

Queste sono due cose diverse, come altri hanno detto.

Quando specifichi# -*- coding: utf-8 -*- , stai dicendo a Python che il file sorgente che hai salvato è utf-8. L'impostazione predefinita per Python 2 è ASCII (per Python 3 è utf-8). Ciò influisce solo sul modo in cui l'interprete legge i caratteri nel file.

In generale, probabilmente non è la migliore idea incorporare caratteri Unicode alti nel file, indipendentemente dalla codifica; puoi usare string unicode escape, che funzionano in entrambe le codifiche.


Quando dichiari una stringa con un udavanti , come u'This is a string', dice al compilatore Python che la stringa è Unicode, non byte. Questo è gestito principalmente in modo trasparente dall'interprete; la differenza più ovvia è che ora puoi incorporare caratteri Unicode nella stringa (ovvero, u'\u2665'ora è legale). Puoi usare from __future__ import unicode_literalsper renderlo predefinito.

Questo si applica solo a Python 2; in Python 3 il valore predefinito è Unicode e devi specificare un bdavanti (come b'These are bytes', per dichiarare una sequenza di byte).


Grazie per la spiegazione! Lo imposterò come accettato poiché è il più completo :)
Oscar Carballal

2
La codifica sorgente predefinita per Python 2 è ascii .
Mark Tolonen

27
In realtà è una buona idea incorporare caratteri Unicode alti nel tuo file. Dubito che i non anglofoni vogliano leggere gli escape Unicode nelle loro stringhe.
Mark Tolonen

@Mark: Grazie per la correzione ASCII; Ho rapidamente sfogliato il PEP ( python.org/dev/peps/pep-0263 ) e nel preambolo si parla di Latin-1. Non penso che sia una buona idea incorporare caratteri Unicode alti nel tuo file nella maggior parte dei casi. Certamente, se stai codificando molte stringhe non inglesi nel tuo file sorgente, può renderlo più semplice, ma generalmente lo fai per la visualizzazione all'utente, e probabilmente dovresti comunque definirle in un posto separato. E un singolo editor di testo mal configurato può corrompere tutti quei caratteri.
Chris B.

4
d'accordo se stai programmando un'app i18nalized, ma considera se sei un programmatore cinese o francese. Non sono solo le stringhe, ma anche i commenti. È fantastico che Python sia flessibile con le codifiche sorgente. Python 3 può anche avere caratteri non ASCII nei nomi delle variabili.
Mark Tolonen

23

Come altri hanno già detto, # coding:specifica la codifica in cui viene salvato il file sorgente. Ecco alcuni esempi per illustrare ciò:

Un file salvato su disco come cp437 (la mia codifica della console), ma nessuna codifica dichiarata

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

Produzione:

  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

Output del file con # coding: cp437aggiunto:

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

All'inizio, Python non conosceva la codifica e si lamentava del carattere non ASCII. Una volta che ha conosciuto la codifica, la stringa di byte ha ottenuto i byte che erano effettivamente sul disco. Per la stringa Unicode, Python legge \ x81, sapeva che in cp437 quello era un ü e lo decodificava nel codepoint Unicode per ü che è U + 00FC. Quando la stringa di byte è stata stampata, Python ha inviato direttamente il valore esadecimale 81alla console. Quando la stringa Unicode è stata stampata, Python ha rilevato correttamente la codifica della mia console come cp437 e ha tradotto Unicode ü nel valore cp437 per ü .

Ecco cosa succede con un file dichiarato e salvato in UTF-8:

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

In UTF-8, ü è codificato come byte esadecimali C3 BC, quindi la stringa di byte contiene quei byte, ma la stringa Unicode è identica al primo esempio. Python ha letto i due byte e li ha decodificati correttamente. Python ha stampato la stringa di byte in modo errato, perché ha inviato i due byte UTF-8 che rappresentano ü direttamente alla mia console cp437.

Qui il file è dichiarato cp437, ma salvato in UTF-8:

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

La stringa di byte ha ancora i byte su disco (byte esadecimali UTF-8 C3 BC), ma li ha interpretati come due caratteri cp437 invece di un singolo carattere codificato UTF-8. Quei due caratteri sono stati tradotti in punti di codice Unicode e tutto viene stampato in modo errato.


10

Ciò non imposta il formato della stringa; imposta il formato del file. Anche con quell'intestazione, "hello"è una stringa di byte, non una stringa Unicode. Per renderlo Unicode, dovrai usarlo u"hello"ovunque. L'intestazione è solo un suggerimento del formato da utilizzare durante la lettura del .pyfile.


Allora mi sbagliavo, pensavo fossero la stessa cosa. Quindi l'uso per le stringhe Unicode è i18n?
Oscar Carballal

@Oscar: Sì, per la maggior parte. Se stavi creando un sito Web con Django o qualcosa del genere e doveva gestire persone con caratteri non ASCII, allora questo è un altro possibile utilizzo.
icktoofay

7

La definizione dell'intestazione consiste nel definire la codifica del codice stesso, non le stringhe risultanti in fase di esecuzione.

l'inserimento di un carattere non ASCII come ۲ nello script python senza la definizione dell'intestazione utf-8 genererà un avviso

errore


-1

Ho realizzato il seguente modulo chiamato unicoder per poter fare la trasformazione sulle variabili:

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

Quindi nel tuo programma potresti fare quanto segue:

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

from unicoder import ustr

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

print type(txt) # <type 'unicode'>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.