Код: Выделить всё
#!/usr/bin/python3
import ctypes
foo = 1
# Should print 2, but prints 1
def print_foo():
global foo
print(foo)
def main():
global foo
foo = 2
dll = ctypes.PyDLL("./foo.so")
foo = dll.foo
foo.restype = None
foo()
if __name__ == "__main__":
main()
Код: Выделить всё
#define PY_SSIZE_T_CLEAN
#include
#include
#define CHECK_PYTHON_ERROR() {\
if (PyErr_Occurred()) {\
PyErr_Print();\
fprintf(stderr, "Error detected in foo.c:%d\n", __LINE__);\
exit(EXIT_FAILURE);\
}\
}
void foo(void) {
PyObject *module = PyImport_ImportModule("main");
CHECK_PYTHON_ERROR();
assert(module);
PyObject *print_foo = PyObject_GetAttrString(module, "print_foo");
CHECK_PYTHON_ERROR();
assert(print_foo);
PyObject *result = PyObject_CallObject(print_foo, NULL);
CHECK_PYTHON_ERROR();
assert(result);
}
Запуск python3.13 main.py выводит 1. Это означает, что оператор foo = 2 не выполнялся в экземпляре, который напечатал foo, что плохо.
Причина, по которой эта программа в настоящее время печатает 1, заключается в том, что поскольку вызов PyImport_ImportModule() (docs) по сути создает новую среду, а не повторно использует исходную.
Изменение на PyImport_AddModule() (docs) или PyImport_AddModuleRef() (документы) печатает это:
Код: Выделить всё
AttributeError: module 'main' has no attribute 'print_foo'
Error detected in foo.c:20
Аналогично PyImport_AddModuleRef() , но возвращает заимствованную ссылку.
И если мы затем посмотрим на PyImport_AddModuleRef его документацию, то увидим вот это фрагмент:
Эта функция не загружает и не импортирует модуль; если модуль еще не был загружен, вы получите пустой объект модуля. Используйте PyImport_ImportModule() или один из его вариантов для импорта модуля.
Похоже, это означает, что AttributeError: модуль 'main' не имеет атрибута ' Ошибка print_foo' была вызвана тем, что модуль не загружался. Однако для меня это не имеет смысла, поскольку использование PyImport_AddModule/
Код: Выделить всё
PyImport_AddModuleRef
Код: Выделить всё
PyObject *g = PyEval_GetGlobals();
CHECK_PYTHON_ERROR();
PyObject *g_repr = PyObject_Repr(g);
CHECK_PYTHON_ERROR();
const char *s = PyUnicode_AsUTF8(g_repr);
CHECK_PYTHON_ERROR();
printf("s: '%s'\n", s);
Код: Выделить всё
s: '{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': '/home/trez/Programming/ctypes-run-bug/main.py', '__cached__': None, 'ctypes': , 'foo': , 'print_foo': , 'main': }'
AttributeError: module 'main' has no attribute 'print_foo'
Error detected in foo.c:28
Я предполагаю, что здесь происходит то, что эти глобальные переменные взяты из исходного экземпляра Python, но Вызов PyImport_AddModule("main") каким-то образом не может найти этот экземпляр.
Как мне сохранить main.py нетронутым при изменении foo.c таким образом, что печатается 2 вместо 1? Приветствую.
Подробнее здесь: https://stackoverflow.com/questions/792 ... on-instanc