Я пишу модуль python в C, и мне нужно, чтобы он вызывал функцию Python с одним из аргументов, переданных "ссылкой". Конечным результатом должно быть то, что функция Python для аргумента будет сохранена в исходной переменной C.
int *resume; // this int is actually passed in to this body of code
PyObject *resumeInt; // which was originally a C callback func for libnids, but
PyObject *ret; // I removed/rewrote most of this code for clarity
resumeInt = Py_BuildValue("i",-1);
ret = PyObject_CallFunction(tcpResumeFunc, "(O)", resumeInt);
*resume = PyInt_AsLong(resumeInt);
Py_DECREF(ret);
Py_DECREF(resumeInt);
Чтобы проверить, у меня была функция Python, которую tcpResumeFunc представляет, модифицирует переданное целое число = 5. Когда я печатаю * возобновление в конце этого кода, однако, он сохраняет его начальное значение -1. Я знаю, что я неправильно понимаю, как работает API. Любые предложения?
Я думаю, вы неправильно понимаете, как работают переменные в Python. Переменные в Python не содержат значений; они ссылаются на них - как на Java, за исключением того, что нет "примитивов" (даже не int
). Присвоение переменной не перезаписывает старое значение; он просто заставляет переменную ссылаться на новое значение и прекращать ссылаться на старый (который затем может быть собран с помощью мусора, если к нему ничего не относится).
Почему бы просто не вернуть (и использовать) значение (поскольку функции Python всегда возвращают что-то в любом случае, даже если это просто неявный возврат None
)?
Изменить: работайте с примером, потому что он слишком длинный для ответа комментария.
Из C мы вызываем PyObject_CallFunction, который передает PyObject * поверх функции Python. В Python параметр функции (мы будем называть его spam
) теперь относится к PyObject с указателем.
Когда мы пишем spam += 6
в функции, это то же самое, что и spam = spam + 6
. Интерпретатор байт-кода получает PyObject, который представляет значение 6, запускает специальный байт-код, который проверяет значение, представленное этими двумя объектами, добавляет их и создает новый PyObject (или выбирает один из кеша), который представляет сумму.
Затем spam
отскакивает от нового объекта; но переменная-ссылка spam
находится на стороне Python забора памяти и не является тем же, что и PyObject * на стороне C забора.
Таким образом, resumeInt
указывает не на вновь созданный/выбранный PyObject.
Фактически он ведет себя точно так же, как он вызывает функцию Python из Python. Попробуйте:
def fry(spam):
spam += 1
eggs = 3
fry(eggs)
eggs # still 3!
Это происходит из-за того, что привязка spam
не влияет на eggs
, которая является отдельной переменной. Мы не проходим мимо ссылки; мы передаем a ссылку по значению. Как и в Java.