¿Qué es la representación interna de la cadena en Python 3.x?
string unicode (7)
Creo que es difícil juzgar la diferencia entre UTF-16, que es solo una secuencia de palabras de 16 bits, en el objeto de cadena de Python.
Y si Python se compila con la opción Unicode = UCS4, se comparará entre UTF-32 y la cadena Python.
Por lo tanto, mejor considerarlos, están en una categoría diferente, aunque pueden transformarse entre sí.
En Python 3.x, una cadena consta de elementos de ordinal de Unicode. (Consulte la cita de la referencia de idioma a continuación.) ¿Cuál es la representación interna de la cadena Unicode? ¿Es UTF-16?
Los elementos de un objeto de cadena son unidades de código Unicode. Una unidad de código Unicode está representada por un objeto de cadena de un elemento y puede contener un valor de 16 bits o de 32 bits que representa un ordinal de Unicode (el valor máximo para el ordinal se da en sys.maxunicode, y depende de cómo sea Python configurado en tiempo de compilación). Los pares sustitutos pueden estar presentes en el objeto Unicode y se informarán como dos elementos separados.
Depende: ver here . Esto sigue siendo cierto para Python 3 en lo que se refiere a la representación interna.
En Python 3.3 y superior, la representación interna de la cadena dependerá de la cadena, y puede ser cualquiera de ascii, latin-1, utf-8, utf-16, utf-32, como lo señala Tobu y se describe en PEP 393 .
Para Pythons anteriores, la representación interna depende de las banderas de construcción de Python. Python puede construirse con valores de bandera --enable-unicode=ucs2
o --enable-unicode=ucs4
. ucs2
construcciones ucs2
de hecho usan UTF-16 como su representación interna , y ucs4
construcciones ucs4
usan UCS-4 / UTF-32.
La representación interna cambiará en Python 3.3, que implementa PEP 393 . La nueva representación seleccionará uno o varios de ascii, latin-1, utf-8, utf-16, utf-32, generalmente tratando de obtener una representación compacta.
Las conversiones implícitas en pares sustitutos solo se realizarán al hablar con las API heredadas (solo existen en Windows, donde wchar_t es de dos bytes); la cadena de Python se conservará. Aquí están las notas de lanzamiento .
Mirando el código fuente de CPython 3.1.5, en Include/unicodeobject.h
:
/* --- Unicode Type ------------------------------------------------------- */
typedef struct {
PyObject_HEAD
Py_ssize_t length; /* Length of raw Unicode data in buffer */
Py_UNICODE *str; /* Raw Unicode buffer */
long hash; /* Hash value; -1 if not set */
int state; /* != 0 if interned. In this case the two
* references from the dictionary to this object
* are *not* counted in ob_refcnt. */
PyObject *defenc; /* (Default) Encoded version as Python
string, or NULL; this is used for
implementing the buffer protocol */
} PyUnicodeObject;
Los caracteres se almacenan como una matriz de Py_UNICODE
. En la mayoría de las plataformas, creo que Py_UNICODE
es #define
d as wchar_t
.
No ha habido CAMBIO en la representación interna de Unicode entre Python 2.X y 3.X.
Definitivamente no es UTF-16. UTF-cualquier cosa es una representación EXTERNA orientada a bytes.
A cada unidad de código (carácter, sustituto, etc.) se le ha asignado un número de rango (0, 2 ** 21). Esto se llama su "ordinal".
Realmente, la documentación que citó lo dice todo. La mayoría de los binarios de Python utilizan ordinales de 16 bits que lo restringen al Plano Multilingüe Básico ("BMP") a menos que quiera jugar con sustitutos (útil si no puede encontrar su camisa de pelo y su lecho de clavos está apagado) oxidado). Para trabajar con el repertorio completo de Unicode, preferiría una "construcción amplia" (32 bits de ancho).
En resumen, la representación interna en un objeto Unicode es una matriz de enteros sin signo de 16 bits, o una matriz de enteros sin signo de 32 bits (utilizando solo 21 bits).
>>> import array; s = ''Привет мир!''; b = array.array(''u'', s).tobytes(); print(b); print(len(s) * 4 == len(b))
b''/x1f/x04/x00/x00@/x04/x00/x008/x04/x00/x002/x04/x00/x005/x04/x00/x00B/x04/x00/x00 /x00/x00/x00</x04/x00/x008/x04/x00/x00@/x04/x00/x00!/x00/x00/x00''
True
>>> import array; s = ''test''; b = array.array(''u'', s).tobytes(); print(b); print(len(s) * 4 == len(b))
b''t/x00/x00/x00e/x00/x00/x00s/x00/x00/x00t/x00/x00/x00''
True
>>>