Warum Unicode per String in Python deklarieren?

122

Ich lerne immer noch Python und habe Zweifel:

In Python 2.6.x deklariere ich normalerweise die Codierung im Dateikopf wie folgt (wie in PEP 0263 ).

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

Danach werden meine Strings wie gewohnt geschrieben:

a = "A normal string without declared Unicode"

Aber jedes Mal, wenn ich einen Python-Projektcode sehe, wird die Codierung nicht im Header deklariert. Stattdessen wird es an jeder Zeichenfolge wie folgt deklariert:

a = u"A string with declared Unicode"

Was ist der Unterschied? Was ist der Zweck davon? Ich weiß, dass Python 2.6.x standardmäßig die ASCII-Codierung festlegt, diese kann jedoch durch die Header-Deklaration überschrieben werden. Wozu dient also die Zeichenfolgendeklaration?

Nachtrag: Scheint, als hätte ich die Dateicodierung mit der Zeichenfolgencodierung verwechselt. Danke, dass du es erklärt hast :)

Oscar Carballal
quelle
6
# coding: utf8ist gut genug, keine Notwendigkeit für-*-
Quallen
1
@ Quallen Ich nehme an, Sie wollten tippen # coding: utf-8.
Samuel Harmer
Sollte sein #coding=utf-8. python.org/dev/peps/pep-0263
Guangtong Shen

Antworten:

167

Das sind zwei verschiedene Dinge, wie andere erwähnt haben.

Wenn Sie angeben# -*- coding: utf-8 -*- , teilen Sie Python mit, welche Quelldatei Sie gespeichert haben utf-8. Die Standardeinstellung für Python 2 ist ASCII (für Python 3 utf-8). Dies wirkt sich nur darauf aus, wie der Interpreter die Zeichen in der Datei liest.

Im Allgemeinen ist es wahrscheinlich nicht die beste Idee, hohe Unicode-Zeichen in Ihre Datei einzubetten, unabhängig von der Codierung. Sie können String-Unicode-Escapezeichen verwenden, die in beiden Codierungen funktionieren.


Wenn Sie eine Zeichenfolge mit einer erklären uvor , wie u'This is a string'es die Python - Compiler sagt , dass die Zeichenfolge Unicode ist die Bytes nicht. Dies wird vom Dolmetscher meist transparent gehandhabt; Der offensichtlichste Unterschied besteht darin, dass Sie jetzt Unicode-Zeichen in die Zeichenfolge einbetten können (das heißt, dies u'\u2665'ist jetzt zulässig). Sie können from __future__ import unicode_literalses als Standard festlegen.

Dies gilt nur für Python 2; In Python 3 ist der Standardwert Unicode, und Sie müssen ein vorangestelltes angeben b(z. B. b'These are bytes'um eine Folge von Bytes zu deklarieren).

Chris B.
quelle
Danke für die Erklärung! Ich werde dies als akzeptiert festlegen, da es das vollständigste ist :)
Oscar Carballal
2
Die Standardquellcodierung für Python 2 ist ascii .
Mark Tolonen
27
Es ist eine großartige Idee, hohe Unicode-Zeichen in Ihre Datei einzubetten. Ich bezweifle, dass nicht englischsprachige Personen Unicode-Escapezeichen in ihren Zeichenfolgen lesen möchten.
Mark Tolonen
@ Mark: Danke für die ASCII-Korrektur; Ich habe das PEP ( python.org/dev/peps/pep-0263 ) schnell überflogen und es wird in der Präambel über Latin-1 gesprochen. Ich halte es in den meisten Fällen nicht für eine gute Idee, hohe Unicode-Zeichen in Ihre Datei einzubetten. Wenn Sie viele nicht-englische Zeichenfolgen in Ihrer Quelldatei codieren, kann dies zwar einfacher sein, aber Sie tun dies im Allgemeinen für die Anzeige für den Benutzer, und Sie sollten diese wahrscheinlich ohnehin an einer separaten Stelle definieren. Und ein einziger falsch konfigurierter Texteditor kann all diese Zeichen beschädigen.
Chris B.
4
vereinbart, wenn Sie eine i18nalisierte App programmieren, aber überlegen Sie, ob Sie ein chinesischer oder französischer Programmierer sind. Es sind nicht nur die Saiten, sondern auch die Kommentare. Es ist großartig, dass Python flexibel mit Quellcodierungen ist. Python 3 kann sogar Nicht-ASCII-Zeichen in Variablennamen enthalten.
Mark Tolonen
23

Gibt, wie andere gesagt haben, # coding:die Codierung an, in der die Quelldatei gespeichert ist. Hier einige Beispiele, um dies zu veranschaulichen:

Eine Datei, die auf der Festplatte als cp437 (meine Konsolencodierung) gespeichert, aber keine Codierung deklariert ist

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

Ausgabe:

  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

Ausgabe der Datei mit # coding: cp437hinzugefügt:

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

Zuerst kannte Python die Codierung nicht und beschwerte sich über das Nicht-ASCII-Zeichen. Sobald die Codierung bekannt war, erhielt die Byte-Zeichenfolge die Bytes, die sich tatsächlich auf der Festplatte befanden. Für die Unicode-Zeichenfolge wusste Python \ x81, dass dies in cp437 ein ü war , und decodierte es in den Unicode-Codepunkt für ü, der U + 00FC ist. Beim Drucken der Byte-Zeichenfolge hat Python den Hex-Wert 81direkt an die Konsole gesendet . Beim Drucken der Unicode-Zeichenfolge hat Python meine Konsolencodierung als cp437 korrekt erkannt und Unicode ü in den cp437-Wert für ü übersetzt .

Folgendes passiert mit einer in UTF-8 deklarierten und gespeicherten Datei:

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

In UTF-8 wird ü als Hex-Byte codiert C3 BC, sodass die Byte-Zeichenfolge diese Bytes enthält, die Unicode-Zeichenfolge jedoch mit dem ersten Beispiel identisch ist. Python hat die beiden Bytes gelesen und korrekt dekodiert. Python hat die Byte-Zeichenfolge falsch gedruckt, da die beiden UTF-8-Bytes, die ü darstellen, direkt an meine cp437-Konsole gesendet wurden.

Hier wird die Datei als cp437 deklariert, aber in UTF-8 gespeichert:

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

Die Byte-Zeichenfolge enthält weiterhin die Bytes auf der Festplatte (UTF-8-Hex-Bytes C3 BC), interpretiert sie jedoch als zwei cp437-Zeichen anstelle eines einzelnen UTF-8-codierten Zeichens. Diese beiden Zeichen wurden in Unicode-Codepunkte übersetzt, und alles wird falsch gedruckt.

Mark Tolonen
quelle
10

Dadurch wird das Format der Zeichenfolge nicht festgelegt. Es legt das Format der Datei fest. Auch mit diesem Header "hello"ist eine Byte-Zeichenfolge keine Unicode-Zeichenfolge. Um es zu Unicode zu machen, müssen Sie es u"hello"überall verwenden. Der Header ist nur ein Hinweis darauf, welches Format beim Lesen der .pyDatei verwendet werden soll.

icktoofay
quelle
Ich habe mich damals geirrt, ich dachte, sie wären gleich. Die Verwendung für Unicode-Strings ist also i18n?
Oscar Carballal
@ Oscar: Ja, zum größten Teil. Wenn Sie eine Website mit Django oder etwas anderem erstellt haben und Personen mit Nicht-ASCII-Zeichen behandeln mussten, ist dies eine weitere mögliche Verwendung.
icktoofay
7

Die Header-Definition definiert die Codierung des Codes selbst und nicht die resultierenden Zeichenfolgen zur Laufzeit.

Wenn Sie ein Nicht-ASCII-Zeichen wie ۲ in das Python-Skript ohne die Definition des utf-8-Headers einfügen, wird eine Warnung ausgegeben

Error

ebt
quelle
-1

Ich habe das folgende Modul namens unicoder erstellt, um die Transformation für Variablen durchführen zu können:

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

Dann könnten Sie in Ihrem Programm Folgendes tun:

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

from unicoder import ustr

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

print type(txt) # <type 'unicode'>
Tecnobillo
quelle