Pourquoi déclarer unicode par chaîne en python?

122

J'apprends toujours python et j'ai un doute:

En python 2.6.x, je déclare généralement le codage dans l'en-tête du fichier comme ceci (comme dans PEP 0263 )

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

Après cela, mes chaînes sont écrites comme d'habitude:

a = "A normal string without declared Unicode"

Mais chaque fois que je vois un code de projet python, l'encodage n'est pas déclaré à l'en-tête. Au lieu de cela, il est déclaré à chaque chaîne comme ceci:

a = u"A string with declared Unicode"

Quelle est la différence? Quel est le but de cela? Je sais que Python 2.6.x définit le codage ASCII par défaut, mais il peut être remplacé par la déclaration d'en-tête, alors à quoi sert la déclaration par chaîne?

Addendum: Il semble que j'ai mélangé l'encodage de fichiers avec l'encodage de chaînes. Merci de l'expliquer :)

Oscar Carballal
la source
6
# coding: utf8est assez bon, pas besoin de-*-
méduses
1
@jellyfish Je suppose que vous vouliez taper # coding: utf-8.
Samuel Harmer
Devrait être #coding=utf-8. python.org/dev/peps/pep-0263
Guangtong Shen

Réponses:

167

Ce sont deux choses différentes, comme d'autres l'ont mentionné.

Lorsque vous spécifiez# -*- coding: utf-8 -*- , vous indiquez à Python le fichier source que vous avez enregistré utf-8. La valeur par défaut pour Python 2 est ASCII (pour Python 3 c'est utf-8). Cela affecte simplement la façon dont l'interpréteur lit les caractères dans le fichier.

En général, ce n'est probablement pas la meilleure idée d'incorporer des caractères Unicode élevés dans votre fichier, quel que soit le codage; vous pouvez utiliser des échappements de chaîne unicode, qui fonctionnent dans les deux encodages.


Lorsque vous déclarez une chaîne avec un udevant , comme u'This is a string', cela indique au compilateur Python que la chaîne est Unicode, pas des octets. Ceci est géré en grande partie de manière transparente par l'interprète; la différence la plus évidente est que vous pouvez désormais incorporer des caractères unicode dans la chaîne (c'est-à-dire qu'elle u'\u2665'est désormais légale). Vous pouvez utiliser from __future__ import unicode_literalspour en faire la valeur par défaut.

Cela ne s'applique qu'à Python 2; dans Python 3, la valeur par défaut est Unicode, et vous devez spécifier un bdevant (comme b'These are bytes', pour déclarer une séquence d'octets).

Chris B.
la source
Merci pour l'explication! Je vais définir ceci comme accepté car c'est le plus complet :)
Oscar Carballal
2
Le codage source par défaut pour Python 2 est ascii .
Mark Tolonen
27
C'est en fait une excellente idée d'incorporer des caractères Unicode élevés dans votre fichier. Je doute que les non-anglophones veuillent lire les échappements Unicode dans leurs chaînes.
Mark Tolonen
@Mark: Merci pour la correction ASCII; J'ai rapidement parcouru le PEP ( python.org/dev/peps/pep-0263 ) et il parle de Latin-1 dans le préambule. Je ne pense pas que ce soit une bonne idée d'incorporer des caractères Unicode élevés dans votre fichier la plupart des cas. Certes, si vous codez beaucoup de chaînes non anglaises dans votre fichier source, cela peut vous faciliter la tâche, mais vous le faites généralement pour les afficher à l'utilisateur, et vous devriez probablement les définir dans un endroit séparé de toute façon. Et un seul éditeur de texte mal configuré peut corrompre tous ces caractères.
Chris B.
4
d'accord si vous programmez une application i18nalisée, mais considérez si vous êtes un programmeur chinois ou français. Ce ne sont pas seulement les chaînes, mais aussi les commentaires. C'est génial que Python soit flexible avec les encodages source. Python 3 peut même avoir des caractères non ASCII dans les noms de variables.
Mark Tolonen
23

Comme d'autres l'ont dit, # coding:spécifie le codage dans lequel le fichier source est enregistré. Voici quelques exemples pour illustrer cela:

Un fichier enregistré sur le disque en tant que cp437 (mon encodage de console), mais aucun encodage déclaré

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

Production:

  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

Sortie du fichier avec # coding: cp437ajouté:

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

Au début, Python ne connaissait pas l'encodage et se plaignait du caractère non ASCII. Une fois qu'elle a connu le codage, la chaîne d'octets a obtenu les octets qui étaient réellement sur le disque. Pour la chaîne Unicode, Python a lu \ x81, savait que dans cp437 c'était un ü , et l'a décodé dans le point de code Unicode pour ü qui est U + 00FC. Lorsque la chaîne d'octets a été imprimée, Python a envoyé la valeur hexadécimale 81directement à la console. Lorsque la chaîne Unicode a été imprimée, Python a correctement détecté le codage de ma console en tant que cp437 et traduit Unicode ü en valeur cp437 pour ü .

Voici ce qui se passe avec un fichier déclaré et enregistré en UTF-8:

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

En UTF-8, ü est codé en octets hexadécimaux C3 BC, la chaîne d'octets contient donc ces octets, mais la chaîne Unicode est identique au premier exemple. Python a lu les deux octets et les a décodés correctement. Python n'a pas imprimé correctement la chaîne d'octets, car il a envoyé les deux octets UTF-8 représentant ü directement à ma console cp437.

Ici, le fichier est déclaré cp437, mais enregistré en UTF-8:

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

La chaîne d'octets contient toujours les octets sur le disque (octets hexadécimaux UTF-8 C3 BC), mais les interprète comme deux caractères cp437 au lieu d'un seul caractère encodé en UTF-8. Ces deux caractères ont été traduits en points de code Unicode et tout ne s'imprime pas correctement.

Mark Tolonen
la source
10

Cela ne définit pas le format de la chaîne; il définit le format du fichier. Même avec cet en-tête, il "hello"y a une chaîne d'octets, pas une chaîne Unicode. Pour le rendre Unicode, vous allez devoir l'utiliser u"hello"partout. L'en-tête n'est qu'une indication du format à utiliser lors de la lecture du .pyfichier.

icktoofay
la source
Je me suis trompé alors, je pensais qu'ils étaient pareils. Donc, l'utilisation des chaînes Unicode est i18n?
Oscar Carballal
@Oscar: Oui, pour la plupart. Si vous créiez un site Web avec Django ou quelque chose du genre et qu'il devait gérer des personnes avec des caractères non ASCII, alors c'est une autre utilisation possible.
icktoofay
7

La définition d'en-tête consiste à définir le codage du code lui-même, pas les chaînes résultantes au moment de l'exécution.

mettre un caractère non-ascii comme ۲ dans le script python sans la définition d'en-tête utf-8 lancera un avertissement

Erreur

ebt
la source
-1

J'ai fait le module suivant appelé unicoder pour pouvoir faire la transformation sur les variables:

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

Ensuite, dans votre programme, vous pouvez effectuer les opérations suivantes:

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

from unicoder import ustr

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

print type(txt) # <type 'unicode'>
Tecnobillo
la source