I wrote a library (dll) in c++ that uses an embedded Python interpreter. Executing Python scripts in the embedded interpreter works fine when the library is used by a c++ program.
If I call the functions of the dll from a Python program I run into trouble. When the dll would usually start the embedded interpreter by calling Py_Initialize() there is an interpreter running already (I can test this by calling Py_IsInitialized() ). When I try to use this interpreter the program crashes.
Minimal example that reproduces the behavior:
Code for dll:
#include "stdafx.h"
#include <Python.h>
extern "C" __declspec(dllexport)
int testIsInitialized()
{
return Py_IsInitialized();
}
extern "C" __declspec(dllexport)
void testRunSimpleString()
{
PyRun_SimpleString("print('test')");
}
Python script:
import ctypes
dll=ctypes.windll.LoadLibrary('pytest.dll')
# test if Python interpreter is initialized
print(dll.testIsInitialized())
# test if we can run a simple Python script
dll.testRunSimpleString()
Output:
1
Traceback (most recent call last):
File "test_dll.py", line 9, in <module>
dll.testRunSimpleString()
OSError: exception: access violation reading 0x0000000000000010
My main question is: How can I execute Python code from a c++ library that is imported by a different Python program?
UPDATE
The example works when I aquire the global interpreter lock (GIL) in my testRunSImpleString() function. I do not understand why this is necessary here.
The ctypes
library has several classes to load different types of DLLs. Two relevant classes are:
ctypes.CDLL
(ie C DLL) - used to load a DLL that uses a standard C calling convention. This includes C++ DLLs that define extern "C"
. ctypes.PyDLL
- similar to C DLL, except that the Python GIL is not released during the function call. Useful to call Python C API functions directly. When loading a C++ DLL that uses the Python C API (ie Python.h
), use ctypes.PyDLL
:
import ctypes
dll = ctypes.PyDLL('pytest.dll')
# then do whatever
dll.testRunSimpleString.argtypes = []
dll.testRunSimpleString.restype = None
dll.testRunSimpleString()
One thing to keep in mind with PyDLL is to that you don't need to call Py_Initialize()
or Py_Finalize()
/ Py_FinalizeEx()
from the C++ API, since the interpreter is already running. You can first check (and store) Py_IsInitialized()
to see if a new interpreter is need to be started/stopped.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.