Короткий ответ: cmd
, вероятно, содержит строку Юникода, которая не может быть преобразована тривиально в const char *
. Сообщение об ошибке, скорее всего, происходит из фреймворка-оболочки, который автоматизирует запись привязок Python для библиотек C, таких как SWIG или ctypes. Структура знает, что делать с байтовой строкой, но называет строки Unicode. Передача str(cmd)
помогает, потому что она преобразует строку Unicode в байтовую строку, из которой значение const char *
, ожидаемое кодом C, может быть тривиально извлечено.
Длинный ответ:
Тип C char const *
, более обычно пишется const char *
, может быть прочитана как «только для чтения массива char
», char
быть путь C, чтобы записать «байт». Когда функция C принимает const char *
, она ожидает «C-строку», то есть массив значений char
, заканчивающийся нулевым символом. Удобно, что строки Python внутренне представлены как строки C с некоторой дополнительной информацией, такой как тип, счетчик ссылок и длина строки (поэтому длину строки можно получить с помощью сложности O (1), а также чтобы строка могла содержать нулевые символы).
Строки Unicode в Python 2 представлены в виде массивов Py_UNICODE
, которые имеют ширину 16 или 32 бит в зависимости от операционной системы и флагов времени сборки. Такой массив не может быть передан в код, который ожидает массив из 8-разрядных символов - он должен быть преобразован, как правило, во временный буфер, и этот буфер должен быть освобожден, когда он больше не нужен.
Например, простодушный (и совсем необязательно) обертка для функции C strlen
может выглядеть следующим образом:
PyObject *strlen(PyObject *ignore, PyObject *obj)
{
const char *c_string;
size_t len;
if (!PyString_Check(obj)) {
PyErr_Format(PyExc_TypeError, "string expected, got %s", Py_TYPE(obj)->tp_name);
return NULL;
}
c_string = PyString_AsString(obj);
len = strlen(c_string);
return PyInt_FromLong((long) len);
}
код просто вызывает PyString_AsString
, чтобы получить внутреннюю строку C сохраненную каждой строки Python и ожидается на strlen
. Для этого кода также поддерживает Unicode объектов (при условии, что даже имеет смысл называть strlen
на объекты Unicode), он должен обращаться с ними в явном виде:
PyObject *strlen(PyObject *ignore, PyObject *obj)
{
const char *c_string;
size_t len;
PyObject *tmp = NULL;
if (PyString_Check(obj))
c_string = PyString_AsString(obj);
else if (PyUnicode_Check(obj)) {
if (!(tmp = PyUnicode_AsUTF8String(obj)))
return NULL;
c_string = PyString_AsString(tmp);
}
else {
PyErr_Format(PyExc_TypeError, "string or unicode expected, got %s",
Py_TYPE(obj)->tp_name);
return NULL;
}
len = strlen(c_string);
Py_XDECREF(tmp);
return PyInt_FromLong((long) len);
}
Обратите внимание на дополнительные сложности, а не только в линиях шаблонного кода, но в различные пути кода, которые требуют различного управления временным объектом, который содержит байтовое представление строки Unicode. Также обратите внимание, что код, необходимый для принятия решения о кодировке при преобразовании строки Unicode в байтовую строку. UTF-8 гарантированно сможет кодировать любую строку Unicode, но передача последовательности, кодированной UTF-8, функции, ожидающей строку C, может не иметь смысла для некоторых целей.Функция str
использует кодек ASCII для кодирования строки Unicode, поэтому, если строка Unicode содержит любые символы, отличные от ASCII, вы получите исключение.
Там было requests to include this functionality in SWIG, но неясно, из связанного отчета, если они сделали это в
Какой тип 'active_call'? Если это unicode, то 'cmd' будет строкой Unicode, а' str (cmd) 'преобразует ее в строку. Вы можете вставить 'import pdb; pdb.set_trace() 'перед вызовом' con.api' и проверьте 'cmd'. – user4815162342
'active_call', скорее всего, unicode, действительно (выходит из базы данных Django), но в этом сообщении об ошибке нет ничего, что заставило меня задуматься о unicode: как вы думаете, это может быть связано? – Anto
Это, безусловно, связано: API, скорее всего, экспортируется через инфраструктуру построения интерфейса, которая знает, как преобразовать строковые объекты Python в 'char const *' (путем вызова 'PyString_AsString' объекта). Строки Unicode Python 2 не состоят из символов C - они состоят из 'wchar_t', что означает, что они не могут быть тривиально« отлиты »от' const char * ', их нужно преобразовать в новый буфер, который должен быть выделен, и т. Д. . Предварительно преобразуя строку Unicode в строку в Python, вы выполняете сложную часть до того, как объект когда-либо достигнет C. – user4815162342