PyUnicode_FromFormat со строками (не в юникоде)

Я пытаюсь создать функцию представления для класса и хочу, чтобы она была совместима с python-2.x и python-3.x. Однако я заметил, что обычные строки при передаче в PyUnicode_FromFormat поскольку %U будет segfault. Единственный жизнеспособный обходной путь, который я нашел, заключался в том, чтобы самостоятельно преобразовать его в объект Unicode с помощью PyUnicode_FromObject и затем передать результат в PyUnicode_FromFormat:

/* key and value are arguments for the function. */
PyObject *repr;
if (PyUnicode_CheckExact(key)) {
    repr = PyUnicode_FromFormat("%U=%R", key, value);
} 
else {
    PyObject *tmp = PyUnicode_FromObject(key);
    if (tmp == NULL) {
        return NULL;
    }
    repr = PyUnicode_FromFormat("%U=%R", tmp, value);
    Py_DECREF(tmp);
}

Дело в том, что я хочу, чтобы представление было без "" (или ''), которые будут добавлены, если я использую %R или %S.

Я только недавно обнаружил проблему, и я использую PyUnicode_FromFormat("%U", something); повсюду, поэтому у меня есть вопрос: можно ли это упростить, сохраняя при этом совместимость с Python 2.x и 3.x?


person MSeifert    schedule 11.03.2017    source источник
comment
У меня нет хорошего ответа на этот вопрос (и я не думаю, что он существует), но у меня возникнет соблазн упростить его, чтобы удалить операторы if и просто каждый раз следовать пути else. Вызов PyUnicode_FromObject для чего-то, что уже является объектом Unicode, просто выполняет incref и возвращает объект обратно, поэтому вам не нужно много делать, чтобы всегда делать это.   -  person DavidW    schedule 13.03.2017
comment
@DavidW Не так просто, как хотелось бы, но это определенно делает его короче и проще. Не могли бы вы добавить это в качестве ответа? Я бы не принял это сразу (все еще надеясь на еще более простой способ), но это определенно полезно.   -  person MSeifert    schedule 13.03.2017
comment
Есть ли проблема с этим кодом? Если нет (т. е. он работает так, как ожидалось), этот вопрос может относиться к обзору кода, а не к переполнению стека.   -  person Fund Monica's Lawsuit    schedule 13.03.2017
comment
@QPaysTaxes CodeReview хочет реальный и работающий код, а не искусственный код. На самом деле я спрашиваю об этом фрагменте кода, и мне не нужен общий обзор кода; так что это будет не по теме обзора кода.   -  person MSeifert    schedule 13.03.2017
comment
(1) Этот код является настоящим, потому что он действительно будет использоваться, а не является псевдо- или усеченным кодом. То, что вы собираетесь заменить им другой код, не имеет значения. (2) я не вижу, как он сломался; если есть проблема, подчеркните ее. (Кроме того, у меня там есть представитель 4k; хотелось бы думать, что я уже знаю, о чем идет речь :))   -  person Fund Monica's Lawsuit    schedule 13.03.2017
comment
@QPaysTaxes Ну, я не согласен только потому, что фактический код который вызвал этот вопрос, отличается (и не готов ни к какому обзору кода)! :-)   -  person MSeifert    schedule 13.03.2017
comment
@MSeifert Я имею в виду, я понимаю, откуда вы, но есть много вопросов по теме - и очень хороших - вопросов о ... ну, не фрагменты, а отдельные функции (что это и есть -- если вы не хотите копировать/вставлять это везде, где вы использовали однострочник). Просто оберните это в информативное имя и дайте некоторый контекст, и все готово. Люди будут ограничивать свои обзоры кодом в самом вопросе.   -  person Fund Monica's Lawsuit    schedule 13.03.2017


Ответы (1)


Я не думаю, что существует очень упрощенный способ делать то, что вы хотите. Лучшее, что я вижу, это исключить оператор if, просто используя ваш случай else и, таким образом, всегда вызывая PyUnicode_FromObject:

PyObject *tmp = PyUnicode_FromObject(key);
if (tmp == NULL) {
    return NULL;
}
repr = PyUnicode_FromFormat("%U=%R", tmp, value);
Py_DECREF(tmp);

Если вы посмотрите на реализация PyUnicode_FromObject, вы Вы увидите, что первое, что он делает, это PyUnicode_CheckExact, и в этом случае он возвращает increfed-версию исходного объекта. Поэтому проделанная дополнительная работа довольно мала (для случая, когда key уже является юникодом), и она должна быть немного более эффективной для случая, когда key не является юникодом, поскольку вы избегаете ветвления.

person DavidW    schedule 13.03.2017