Мне нужно написать высокопроизводительную логику обработки Unicode, и различия между python2 и объектом Unicode в python3 значительны.
Я только начинаю выяснять, как это сделать, и следующий фрагмент даетУ меня проблема:
from six.text_type import unicode
from cpython.version cimport PY_MAJOR_VERSION
cdef extern from "Python.h":
int PyUnicode_KIND ( object o )
def unicode_size ( unicode u ):
if PY_MAJOR_VERSION == 2:
return sizeof ( Py_UNICODE )
else:
return PyUnicode_KIND ( u )
Этот код выполняется и выполняется как в Python 2, так и в 3. Однако компилятор Python2 c выдает «предупреждение C4013:« PyUnicode_KIND »не определено; предполагается, что extern возвращает int»
Обычно я мог бы подавить такого рода предупреждения, дав компилятору c внешнее объявление для функции, зная, что компоновщик вызовет истерику, если я на самом деле попытаюсь связать его.
Однако я могу 'Не могу понять, как создавать внешние объявления внутри Cython, чтобы компилятор был доволен.
Меня не интересует отключение предупреждения с помощью параметров командной строки, я стараюсь сделать компиляцию простой и понятной.вперед, и я один из тех "предупреждений об ошибках" фанатиков.Эта логика достаточно проста, чтобы поместиться в один файл pyx.Кроме того, преобладает мнение, что сгенерированный код C должен компилироваться как в Python 2, так и в Python 3, поэтому я стараюсь придерживаться этого.
Чтобы сделать вещи еще более нелепыми, когда я смотрю на сгенерированныйC-код, есть __Pyx_PyUnicode_KIND (), который делает именно то, что я хочу, но если я пытаюсь вызвать это из моего кода Cython, он говорит, что его не существует.Если вышесказанное невозможно, могу ли я получить доступ к этим макросам переносимости?
Может быть, я ни о чем не говорю.Очевидно, преждевременная оптимизация - это дьявол, но мой ограниченный опыт пока заключается в том, что для максимальной производительности мне нужно получить доступ к указателям за объектами python, иначе защитные оболочки абсолютно снижают производительность.Есть ли другой способ обработки ввода Unicode и создания другого вывода Unicode без обращения к специфическому для версии C apis?
---------- ОБНОВЛЕНИЕ ---------
Благодаря @ead я смог разработать решение, отвечающее всем моим критериям.Для всех, кто хочет накапливать символы UCS4 в буфере в Cython, а затем преобразовывать его в объект Unicode, когда это будет сделано, я решил эту проблему в своем файле .pyx:
cdef extern from *:
"""
// This is C code that will be passed through to xmlwalk.c as-is:
PyObject* PyUnicode_FromUCS4 ( Py_UCS4* s, Py_ssize_t size )
{
#if PY_VERSION_HEX >= 0x03030000
return PyUnicode_FromKindAndData ( PyUnicode_4BYTE_KIND, s, size );
#elif Py_UNICODE_SIZE == 4
return PyUnicode_FromUnicode ( s, size );
#elif Py_UNICODE_SIZE == 2
// WARNING: this version of the code rewrites s in-place as UTF-16.
// `s` no longer contains valid UCS4 code points upon return.
Py_UNICODE* dst = (Py_UNICODE*)s;
Py_ssize_t dst_size = 0;
Py_ssize_t i;
for ( i = 0; i < size; i++ )
{
Py_UCS4 c = s[i];
//printf ( "src[%i]=%i (0x%x)\\n", i, (int)c, (int)c );
if ( c < 0x10000 )
{
// assert ( c < 0xD800 || c > 0xDFFF ); // disabled for performance reasons
dst[dst_size++] = (Py_UNICODE)c;
//printf ( "dst[%i]=%i (0x%x)\\n", dst_size-1, (int)dst[dst_size-1], (int)dst[dst_size-1] );
}
else
{
dst[dst_size++] = 0xD800 | (c >> 10);
//printf ( "dst[%i]=%i (0x%x)\\n", dst_size-1, (int)dst[dst_size-1], (int)dst[dst_size-1] );
dst[dst_size++] = 0xDC00 | (c & 0x3FF);
//printf ( "dst[%i]=%i (0x%x)\\n", dst_size-1, (int)dst[dst_size-1], (int)dst[dst_size-1] );
}
}
return PyUnicode_FromUnicode ( dst, dst_size );
#else
assert(0); // could not determine correct unicode type
#endif
}
"""
PyObject* PyUnicode_FromUCS4 ( Py_UCS4* s, Py_ssize_t size )