3.9 KiB
icon | label | order |
---|---|---|
code | C++ | 10 |
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
PyObject* result = vm->exec("sum(a)", "<eval>", EVAL_MODE);
std::cout << py_cast<i64>(vm, result); // 6
return 0;
}
Interop with PyObject*
In PkPy, any python object is represented by a PyObject*
.
VAR(...)
, create aPyObject*
from a C typeCAST(T, ...)
, cast aPyObject*
to a C type_CAST(T, ...)
, cast aPyObject*
to a C type, without type check
PyObject* x = VAR(12); // cast a C int to PyObject*
int y = CAST(int, x); // cast a PyObject* to C int
PyObject* i = VAR("abc");
std::cout << CAST(Str, i); // abc
Types
PyObject type |
C type | note |
---|---|---|
int |
i64 |
62 bits integer |
float |
f64 |
62 bits floating point |
str |
pkpy::Str |
|
bool |
bool |
|
list |
pkpy::List |
|
tuple |
pkpy::Tuple |
|
function |
pkpy::Function |
|
... | ... | ... |
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 C function pointer for native functions:
typedef PyObject* (*NativeFuncC)(VM*, ArgsView);
The first argument is the pointer of VM
instance.
The second argument is a view of an array. 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 PyObject*
, 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, ArgsView args){
static std::string line;
std::getline(std::cin, line);
return VAR(line);
});
// vvv function name
vm->bind_builtin_func<2>("add", [](VM* vm, ArgsView args){
// ^ argument count
i64 lhs = CAST(i64, args[0]);
i64 rhs = CAST(i64, args[1]);
return VAR(lhs + rhs);
});
Call a Python Function
Use these to call a python function.
PyObject* VM::call(PyObject* obj, ...)
PyObject* VM::call_method(PyObject* obj, StrName name, ...)
For example, to create a dict
object,
PyObject* tp = vm->builtins->attr("dict");
PyObject* obj = vm->call(tp); // this is a `dict`
And set a key-value pair,
vm->call_method(obj, "__setitem__", VAR("a"), VAR(5));
PyObject* ret = vm->call(obj, "__getitem__", VAR("a"));
std::cout << CAST(int, ret) << std::endl; // 5
Attribute Access
There are 3 methods for this.
PyObject* VM::getattr(PyObject*, StrName)
void VM::setattr(PyObject*, StrName, PyObject*)
PyObject* VM::get_unbound_method(PyObject*, StrName, PyObject**)
Wrapping a struct
as PyObject
!!!
This feature is unstable.
!!!