Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local ffi = assert(require("ffi"))
- local PYTHON = assert(ffi.load("libpython3.5m.so", true))
- ffi.cdef[[
- typedef void PyCompilerFlags;
- typedef struct _object {
- size_t ob_refcnt;
- struct _typeobject *ob_type;
- } PyObject;
- // Types
- typedef struct _typeobject PyTypeObject;
- PyTypeObject _PyNone_Type;
- PyTypeObject PyLong_Type;
- PyTypeObject PyUnicode_Type;
- PyTypeObject PyFloat_Type;
- // Initialization
- void Py_Initialize();
- void Py_Finalize();
- void PyErr_Print();
- PyObject * PyEval_GetBuiltins();
- void _Py_Dealloc(PyObject *);
- // Dictionary functions
- PyObject * PyDict_New();
- PyObject * PyDict_GetItemString(PyObject *, const char *);
- int PyDict_SetItemString(PyObject *, const char *, PyObject *);
- // Conversion
- long PyLong_AsLong(PyObject *);
- double PyFloat_AsDouble(PyObject *);
- PyObject* PyUnicode_AsASCIIString(PyObject *);
- char* PyBytes_AsString(PyObject *);
- // Execution
- PyObject * PyRun_StringFlags(const char *, int, PyObject *, PyObject *, PyCompilerFlags *);
- ]]
- local python_initialized = false
- function Python()
- -- Initialize the Python interpreter (singleton)
- PYTHON.Py_Initialize()
- if python_initialized then
- error("There can only be one!")
- end
- python_initialized = true
- -- Allocate a dictionary for locals and globals
- local locals = PYTHON.PyDict_New()
- local globals = PYTHON.PyDict_New()
- -- Import builtins into global (otherwise things like "print" are missing)
- if (PYTHON.PyDict_GetItemString(globals, "__builtins__") == NULL) then
- if (PYTHON.PyDict_SetItemString(globals, "__builtins__",
- PYTHON.PyEval_GetBuiltins()) ~= 0) then
- error("Could not import builtins!")
- end
- end
- -- Magic numbers
- local Py_file_input = 257
- local Py_eval_input = 258
- -- XDECREF is a macro, thus we have to reimplement it
- local function Py_XDECREF(_py_decref_tmp)
- if _py_decref_tmp ~= nil then
- _py_decref_tmp.ob_refcnt = _py_decref_tmp.ob_refcnt - 1
- if _py_decref_tmp.ob_refcnt == 0 then
- PYTHON._Py_Dealloc(_py_decref_tmp)
- end
- end
- end
- -- Evaluate a single statement and get the result
- local function get(expr)
- local r = PYTHON.PyRun_StringFlags(expr,Py_eval_input,globals,locals,nil)
- local value = nil
- if r == nil then
- -- Check for errors
- PYTHON.PyErr_Print()
- error("Python error!")
- else
- -- Convert last result
- if r.ob_type == PYTHON._PyNone_Type then
- value = nil
- elseif r.ob_type == PYTHON.PyLong_Type then
- value = tonumber(PYTHON.PyLong_AsLong(r))
- elseif r.ob_type == PYTHON.PyFloat_Type then
- value = tonumber(PYTHON.PyFloat_AsDouble(r))
- elseif r.ob_type == PYTHON.PyUnicode_Type then
- local pystr = PYTHON.PyUnicode_AsASCIIString(r)
- local str = PYTHON.PyBytes_AsString(pystr)
- value = ffi.string(str)
- Py_XDECREF(pystr)
- else
- error("Unknown type at " .. tostring(r.ob_type))
- end
- end
- Py_XDECREF(r)
- return value
- end
- -- Evaluate a block of code (no return value)
- local function run(expr)
- local r = PYTHON.PyRun_StringFlags(expr,Py_file_input,globals,locals,nil)
- if r == nil then
- PYTHON.PyErr_Print()
- error("Python error!")
- end
- Py_XDECREF(r)
- end
- -- Evaluate a block of code and retrieve whatever is stored in the
- -- variable "result"
- local function eval(expr)
- run(expr)
- return get"result"
- end
- -- Register garbage collection in the finalizer
- local metatable = {
- __gc = function()
- Py_XDECREF(locals)
- Py_XDECREF(globals)
- PYTHON.Py_Finalize()
- end
- }
- -- Export functions
- local instance = { run = run, get = get, eval = eval }
- setmetatable(instance, metatable)
- return instance
- end
- --[[
- To create a new Python interpreter, call Python(), which returns a
- table with functions. I'm not so sure about Python's memory
- management, that's why it is a singleton.
- Available functions:
- Python:get(string)
- Runs a single Python statement and returns the result as a Lua
- type. Supported types are None, Int, Float, String.
- Python:run(string)
- Runs a block of Python code. Useful for defining functions or
- importing modules. Does not return a result.
- Python:eval(string)
- Sort of combines the above. Runs a block of Python code and
- returns whatever has been stored in the variable "result". Will
- crash if "result" is not defined.
- --]]
- local python = Python()
- python.run[[
- from scipy.integrate import quad
- def integrand(x, a, b):
- return a*x**2 + b
- ]]
- a = 2
- b = 1
- local v = python.get("quad(integrand, 0, 1, args=(" .. a .. "," .. b .. "))[0]")
- print(v)
Add Comment
Please, Sign In to add comment