pocketpy is a portable Python 3.x interpreter, written in C11 - by blueloveTH. It aims to be an alternative to Lua for game scripting, with elegant syntax, powerful features and competitive performance. pocketpy has no dependencies other than the C standard library, which can be easily integrated into your C/C++ project. Developers are able to write Python bindings via C-API or pybind11 compatible interfaces.
Please see https://pocketpy.dev for details and try the following resources.
- Live Python Demo: Run Python code in your browser
- Live C Examples: Explore C-APIs in your browser
- Godot Extension: Use pocketpy in Godot Engine
- VSCode Extension: Debug and profile pocketpy scripts in VSCode
- Flutter Plugin: Use pocketpy in Flutter apps
Run:
$ npm i pocketpy.cAnd then include pocketpy.h as follows:
#include "node_modules/pocketpy.c/pocketpy.h"You may also want to include pocketpy.c as follows:
#ifndef __POCKETPY_C__
#define __POCKETPY_C__
#include "node_modules/pocketpy.c/pocketpy.c"
#endifThis will include both the function declaration and their definitions into a single file.
pkpy should work on any platform with a C11 compiler. These platforms are officially tested.
- Windows 64-bit
- Linux 64-bit / 32-bit
- macOS 64-bit
- Android 64-bit / 32-bit
- iOS 64-bit
- Emscripten 32-bit
- Raspberry Pi OS 64-bit
You have two options to integrate pkpy into your project.
Include the pocketpy.h and pocketpy.c in your project.
Clone the whole repository as a submodule into your project, In your CMakelists.txt, add the following lines:
add_subdirectory(pocketpy)
target_link_libraries(<your_target> pocketpy)See CMakeLists.txt for details.
It is safe to use main branch in production if CI badge is green.
To compile it with your project, these flags must be set:
--std=c11flag must be set- For MSVC,
/utf-8and/experimental:c11atomicsflag must be set NDEBUGmacro should be defined for release build, or you will get poor performance
For amalgamated build, run python amalgamate.py to generate pocketpy.c and pocketpy.h in amalgamated/ directory.
#include "pocketpy.h"
#include <stdio.h>
static bool int_add(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
PY_CHECK_ARG_TYPE(0, tp_int);
PY_CHECK_ARG_TYPE(1, tp_int);
py_i64 a = py_toint(py_arg(0));
py_i64 b = py_toint(py_arg(1));
py_newint(py_retval(), a + b);
return true;
}
int main() {
// Initialize pocketpy
py_initialize();
// Hello world!
bool ok = py_exec("print('Hello world!')", "<string>", EXEC_MODE, NULL);
if(!ok) goto __ERROR;
// Create a list: [1, 2, 3]
py_Ref r0 = py_getreg(0);
py_newlistn(r0, 3);
py_newint(py_list_getitem(r0, 0), 1);
py_newint(py_list_getitem(r0, 1), 2);
py_newint(py_list_getitem(r0, 2), 3);
// Eval the sum of the list
py_Ref f_sum = py_getbuiltin(py_name("sum"));
py_push(f_sum);
py_pushnil();
py_push(r0);
ok = py_vectorcall(1, 0);
if(!ok) goto __ERROR;
printf("Sum of the list: %d\n", (int)py_toint(py_retval())); // 6
// Bind native `int_add` as a global variable
py_newnativefunc(r0, int_add);
py_setglobal(py_name("add"), r0);
// Call `add` in python
ok = py_exec("add(3, 7)", "<string>", EVAL_MODE, NULL);
if(!ok) goto __ERROR;
py_i64 res = py_toint(py_retval());
printf("Sum of 2 variables: %d\n", (int)res); // 10
py_finalize();
return 0;
__ERROR:
py_printexc();
py_finalize();
return 1;
}| Name | Example | Supported |
|---|---|---|
| If Else | if..else..elif |
✅ |
| Loop | for/while/break/continue |
✅ |
| Function | def f(x,*args,y=1): |
✅ |
| Subclass | class A(B): |
✅ |
| List | [1, 2, 'a'] |
✅ |
| ListComp | [i for i in range(5)] |
✅ |
| Slice | a[1:2], a[:2], a[1:] |
✅ |
| Tuple | (1, 2, 'a') |
✅ |
| Dict | {'a': 1, 'b': 2} |
✅ |
| F-String | f'value is {x}' |
✅ |
| Unpacking | a, b = 1, 2 |
✅ |
| Star Unpacking | a, *b = [1, 2, 3] |
✅ |
| Exception | raise/try..except.. |
✅ |
| Dynamic Code | eval()/exec() |
✅ |
| Reflection | hasattr()/getattr()/setattr() |
✅ |
| Import | import/from..import |
✅ |
| Context Block | with <expr> as <id>: |
✅ |
| Type Annotation | def f(a:int, b:float=1) |
✅ |
| Generator | yield i |
✅ |
| Decorator | @cache |
✅ |
| Match Case | match code: case 200: |
✅ |
Currently, pkpy is as fast as cpython 3.9. Performance results for cpython 3.9 are applicable to for pkpy.
See https://pocketpy.dev/performance/ for details.
And these are the results of the primes benchmark on Intel i5-12400F, WSL (Ubuntu 20.04 LTS), which roughly reflects the performance among c++, lua, pkpy and cpython.
| name | version | time | file |
|---|---|---|---|
| c++ | gnu++11 | 0.104s ■□□□□□□□□□□□□□□□ |
benchmarks/primes.cpp |
| lua | 5.3.3 | 1.576s ■■■■■■■■■□□□□□□□ |
benchmarks/primes.lua |
| pkpy | 1.2.7 | 2.385s ■■■■■■■■■■■■■□□□ |
benchmarks/primes.py |
| cpython | 3.8.10 | 2.871s ■■■■■■■■■■■■■■■■ |
benchmarks/primes.py |
| Description | |
|---|---|
| godot-pocketpy | Godot extension for using pocketpy in Godot Engine. |
| TIC-80 | TIC-80 is a fantasy computer for making, playing and sharing tiny games. |
| py-js | Python3 externals for Max / MSP. |
| crescent | Crescent is a cross-platform 2D fighting and beat-em-up game engine. |
| orxpy | Python extension for orx engine. |
| CANopenTerm | Open-source software tool for CANopen CC networks and devices. |
Submit a pull request to add your project here.
All kinds of contributions are welcome.
- Submit a Pull Request
- fix a bug
- add a new feature
- Open an Issue
- any suggestions
- any questions
If you find pkpy useful, consider star this repository (●'◡'●)
You can sponsor this project via these ways.
Your sponsorship will help us develop pkpy continuously.
-
The official implementation of Python programming language.
-
An excellent learning material. It illustrates how Python's virtual machine works.