#
C++
For C++ developers, you can download the pocketpy.h
on our GitHub release page.
https://github.com/blueloveTH/pocketpy/releases/latest
#
Example
#include "pocketpy.h"
using namespace pkpy;
int main(){
// Create a virtual machine
VM* vm = new VM(true);
// Hello world!
vm->exec("print('Hello world!')", "main.py", EXEC_MODE);
// Create a list
vm->exec("a = [1, 2, 3]", "main.py", EXEC_MODE);
// Eval the sum of the list
PyVar result = vm->exec("sum(a)", "<eval>", EVAL_MODE);
std::cout << py_cast<i64>(vm, result); // 6
return 0;
}
#
Interop with PyVar
In PocketPy, any python object is represented by a PyVar
.
VAR(...)
, create aPyVar
from a C typeCAST(T, ...)
, cast aPyVar
to a C type_CAST(T, ...)
, cast aPyVar
to a C type, without type check
PyVar x = VAR(12); // cast a C int to PyVar
int y = CAST(int, x); // cast a PyVar to C int
PyVar i = VAR("abc");
std::cout << CAST(Str, i); // abc
#
Types
#
Bind a Native Function
In VM
class, there are 4 methods to bind native function.
VM::bind_func<ARGC>
VM::bind_builtin_func<ARGC>
VM::bind_method<ARGC>
VM::bind_static_method<ARGC>
They are all template methods, the template argument is a int
number, indicating the argument count. For variadic arguments, use -1
. For methods, ARGC
do not include self
.
Native functions do not support keyword arguments.
PkPy uses a universal function type for native functions:
std::function<PyVar(VM*, Args&)>
The first argument is the pointer of VM
instance.
The second argument is a special array, a restricted and optimized std::vector<PyVar>
. You can use []
operator to get the element. If you have specified ARGC
other than -1
, the interpreter will ensure args.size() == ARGC
. No need to do size check.
The return value is a PyVar
, which should not be nullptr
. If there is no return value, return vm->None
.
This is an example of binding the input()
function to the builtins
module.
VM* vm = pkpy_new_vm(true);
vm->bind_builtin_func<0>("input", [](VM* vm, Args& args){
static std::string line;
std::getline(std::cin, line);
return VAR(line);
});
#
Bind a Native Function with Proxy
For simple functions, you can use ProxyFunc
to simplify the binding process. A ProxyFunc
is a wrapper of a native function. It can be constructed from a function pointer, a lambda function, or a std::function
.
It will automatically call VAR(...)
and CAST(T, ...)
when necessary.
double add(int a, double b){
return a + b;
}
vm->bind_builtin_func<2>("add", NativeProxyFunc(&add));
#
Call a Python Function
Use these to call a python function.
// call a python function to get its result
vm::call(const PyVar& obj, const Str& func, Args args);
// call a python class to create an instance
vm::call(const PyVar& obj);
For example, to create a dict
object,
const PyVar& tp = vm->builtins->attr("dict");
PyVar obj = vm->call(tp); // this is a `dict`
And set a key-value pair,
call(obj, "__setitem__", two_args(VAR("a"), VAR(5)));
PyVar ret = call(obj, "__getitem__", one_arg(VAR("a")));
std::cout << CAST(int, ret) << std::endl; // 5
#
Wrapping a struct
as PyObject
This feature is unstable.