Правильность Python в C API

Кажется, что Python C API не согласуется с константной корректностью символьных массивов. Например, PyImport_ImportFrozenModule принимает char*, в то время как PyImport_ImportModule принимает const char*,

Следствием всего этого является то, что в моем приложении C ++, которое я пишу со встроенным интерпретатором Python, мне иногда приходится приводить строковый литерал, который я передаю, к вызову Python API как char* (в отличие от const char*), а иногда нет. Например:

PyObject *os = PyImport_ImportModule("os"); // Works without the const_cast
PyObject *cwd = PyObject_CallMethod(os, const_cast<char*>("getcwd"), NULL); // Accepts char*, not const char*

Если я не сделаю const_cast<char*> (или же (char*)) в строковом литерале я получаю предупреждение компилятора о приведении строковых литералов в char*,

Вот мои вопросы:

  1. Есть ли преимущество / причина того, что некоторые функции не const char* (и / или почему бы Python API не был последовательным в этом)? Насколько я понимаю, что если функция может принимать строковый литерал, она не может изменить char* Итак const Модификатор будет только усиливать это. Я также считаю, что const Различие не так важно для C (для которого был написан API), чем для C ++ (поправьте меня, если я ошибаюсь … моя сила в Python, а не в C / C ++). Является ли отсутствие «правильной константности» Python API, потому что это просто не так важно в C? (Есть старая ветка в списке рассылки python с 2000 года, задавая тот же вопрос, но он, похоже, никуда не ушел, и подразумевается, что причина может быть в том, что некоторые компиляторы не поддерживают const, Поскольку многие функции теперь имеют const char*кажется, это больше не применимо)
  2. Поскольку мое понимание C ++ ограничено, я не уверен, правильно ли я приведу строковые литералы. На мой взгляд, я могу выполнить одно из следующих действий (сейчас я делаю первый):

    // Method 1) Use const_cast<char*>
    PyImport_ImportFrozenModule(const_cast<char*>("mymodule"));
    
    // Method 2) Use (char*)
    PyImport_ImportFrozenModule((char*) "mymodule");
    
    // Method 3) Use char array
    char mod[] = "mymodule";
    PyImport_ImportFrozenModule(mod);
    

    Какой метод лучше использовать?


Обновить:

Похоже, ветка Python3 медленно пытается исправить проблему правильности констант. Например, PyImport_ImportFrozenModule Функция, которую я использую в качестве примера выше, теперь занимает const char* в Python 3.4, но все еще есть функции, которые принимают только char*, такие как PyLong_FromString.

8

Решение

Судя по некоторым разговорам в списке рассылки от python-dev, похоже, что первоначальный API просто не был создан с учетом константности, вероятно, просто потому, что Гвидо не думал об этом. Встречаясь в 2002 году, кто-то спросил если было желание решить эту проблему, добавив const -корректность, жалуясь, что всегда приходится делать это так:

somefunc(const char* modulename, const char* key)
{
... PyImport_ImportModule(const_cast<char*>(modulename)) ...

Гвидо Ван Россум (создатель Python) ответил (выделение мое):

Я никогда не пытался применить константность, но я слышал
достаточно ужасных историй об этом. Проблема в том, что он ломает 3-й
партийные расширения влево и вправо, и исправить их не всегда просто.
В общем, всякий раз, когда вы добавляете const где-то, это заканчивается распространением
к другому API, который затем также требует const, который распространяется
еще одному API, нуждающемуся в const, до бесконечности.

Было немного больше дискуссий, но без поддержки Гвидо идея умерла.

Перенесемся на девять лет, и тема снова возникла. На этот раз кто-то просто задавался вопросом, почему некоторые функции были правильными, а другие — нет. Один из разработчиков ядра Python ответил с этим:

На протяжении многих лет мы добавляли const во многие места. я думаю
конкретный случай был пропущен (т.е. никто не заботился о добавлении const
там).

Кажется, что когда это можно было бы сделать, не нарушая обратную совместимость, const -корректность была добавлена ​​во многие места в C API (и в случае с Python 3, в местах, где это было бы нарушить обратную совместимость с Python 2), но глобальных усилий по ее устранению не было везде. Таким образом, ситуация лучше в Python 3, но весь API, вероятно, не является правильным даже сейчас.

Я не думаю, что у сообщества Python есть какой-либо предпочтительный способ обрабатывать приведение с вызовами, которые не являются const-правильно (нет упоминания об этом в официальном Руководство по стилю C-API), вероятно, потому, что нет тонны людей, взаимодействующих с C-API из кода C ++. Я бы сказал, что предпочтительным способом сделать это с точки зрения передового опыта в чистом C ++ будет первый выбор. (Я ни в коем случае не эксперт C ++, так что возьмите это с крошкой соли).

4

Другие решения

Есть ли преимущество / причина того, что некоторые функции не const char*?

Нет. Выглядит как упущение в дизайне библиотеки или, как вы говорите, унаследованные проблемы. Хотя бы они могли сделать это непротиворечивым!

Насколько я понимаю, что если функция может принимать строковый литерал, она не может изменить char* Итак const Модификатор будет только усиливать это.

Именно так. В их документации также должно быть указано, что аргумент функции (или, скорее, аргумент аргумента) не должен изменяться во время вызова функции; увы это сейчас не говорит об этом.

Я также считаю, что const Различие не так важно для C (для которого был написан API), чем для C ++.

Ну, не совсем, по крайней мере, насколько я знаю.

На мой взгляд, я могу выполнить одно из следующих действий (сейчас я делаю первый)

(хорошо)

Какой метод лучше использовать?

Хорошо const_cast по крайней мере, убедитесь, что вы только модифицирование constКонечно, если бы тебе пришлось выбирать, я бы пошел с этим. Но, на самом деле, я бы не стал слишком беспокоиться об этом.

3

По вопросам рекламы [email protected]