pyobj.h is a single-header C++ library that provides Python-like syntax for embedding Python in C++ applications.
Native Python/C API is verbose and error-prone:
// Traditional Python C API — painful!
PyObject* list = PyList_New(0);
PyList_Append(list, PyLong_FromLong(42));
PyObject* item = PyList_GetItem(list, 0);
long value = PyLong_AsLong(item);
Py_DECREF(item);
Py_DECREF(list);With pyobj.h — clean and intuitive:
// pyobj.h — writes like Python!
py::List list;
list.append(42);
long value = list[0]; // Automatic conversion!| Principle | Implementation |
|---|---|
| RAII Memory Management | Automatic Py_XINCREF/Py_XDECREF |
| Operator Overloading | [], (), +, *, ==, !=, <, >, ` |
| Implicit Conversions | C++ types ↔ Python objects |
| Python-like Methods | .append(), .pop(), .keys(), .upper(), .split() |
| Variadic Templates | operator() accepts any number/type of arguments |
| Formatted Strings | py::fstring("Hello {name}!", py::farg("name", "World")) |
| Class | Python Equivalent | Key Methods |
|---|---|---|
py::PyObj |
object |
Base class, operator[], operator(), str(), is_*() |
py::Str |
str |
upper(), lower(), split(), join(), find(), replace() |
py::List |
list |
append(), pop(), extend(), sort(), reverse(), index() |
py::Tuple |
tuple |
index(), count(), to_list(), operator[] |
py::Set |
set |
add(), pop(), union_with(), intersection(), difference() |
py::Dict |
dict |
get(), set(), pop(), keys(), values(), items(), update() |
py::Function |
callable |
call(), operator() with kwargs support |
| Function | Python Equivalent | Description |
|---|---|---|
py::print(obj) |
print() |
Print any Python object |
py::pprint(obj) |
pprint.pprint() |
Pretty-print with indentation |
py::len(obj) |
len() |
Get length of sequence/collection |
py::type(obj) |
type() |
Get type name as string |
py::sorted(seq) |
sorted() |
Return sorted list |
py::reversed(obj) |
reversed() |
Return reversed sequence |
py::all(list) |
all() |
True if all elements are truthy |
py::any(list) |
any() |
True if any element is truthy |
py::map(func, list) |
map() |
Apply function to each element |
py::exec(code) |
exec() |
Execute Python code string |
py::eval(code) |
eval() |
Evaluate Python expression |
py::run_file(path) |
exec(open().read()) |
Execute Python file |
| Function | Description |
|---|---|
py::json_dump(obj, filename, indent) |
Write object to JSON file |
py::json_dumps(obj) |
Convert object to JSON string |
py::json_load(filename) |
Read JSON file to Python object |
py::json_loads(json_string) |
Parse JSON string to Python object |
std::string result = py::fstring(
"Hello {name}! You are {age} years old.",
py::farg("name", "Alice"),
42 // positional argument
);
// Result: "Hello Alice! You are 42 years old."Single-header library — just copy pyobj.h to your project!
wget https://raw.githubusercontent.com/vk-candpython/pyobj/main/pyobj.h# Find Python development headers
g++ -std=c++17 main.cpp -o main $(python3-config --includes --ldflags)#include "pyobj.h"
int main() {
py::init_python();
// Create and manipulate Python objects
py::List my_list = {1, 2, 3, "hello"};
my_list.append(42);
py::print(my_list); // [1, 2, 3, 'hello', 42]
// Call Python functions
py::Function len = py::eval("len");
std::cout << "Length: " << len(my_list).str() << std::endl;
py::exit_python();
return 0;
}Base class for all Python objects with automatic reference counting.
// Construction from C++ types
py::PyObj a = 42; // int
py::PyObj b = 3.14; // float
py::PyObj c = true; // bool
py::PyObj d = "hello"; // string
// Type checking
if (a.is_str()) { /* ... */ }
if (b.is_list()) { /* ... */ }
if (c.is_callable()) { /* ... */ }
// Indexing (works for dict, list, tuple, string)
py::PyObj value = obj["key"]; // dict access
py::PyObj item = obj[0]; // list/tuple/string access
// Universal call operator
py::Function func = py::eval("print");
func("Hello", "World", py::Dict{{"end", "!\n"}});
// String representation
std::string s = obj.str();
std::cout << obj << std::endl; // Uses repr()py::Str s = "Hello World";
// Case operations
py::Str upper = s.upper(); // "HELLO WORLD"
py::Str lower = s.lower(); // "hello world"
py::Str title = s.title(); // "Hello World"
// Validation
bool is_digit = s.isdigit();
bool is_alpha = s.isalpha();
// Search
long pos = s.find("World"); // 6
py::Str replaced = s.replace("World", "C++");
// Split and join
std::vector<py::Str> parts = s.split(" "); // ["Hello", "World"]
py::Str joined = py::Str("-").join(parts); // "Hello-World"
// Length
long len = s.len(); // 11
// Concatenation
py::Str result = s + " from C++";
s += "!";
// Repetition
py::Str stars = py::Str("*") * 10; // "**********"// Construction
py::List list = {1, 2, 3, "four", 5.0};
// Modification
list.append(42);
list.extend({6, 7, 8});
list.insert(0, "first");
list.remove("four");
// Access
py::PyObj item = list[0];
py::PyObj popped = list.pop(); // removes last
py::PyObj popped2 = list.pop(1); // removes at index
// Search
long idx = list.index(42);
long count = list.count(1);
bool has = list.contains(3);
// Manipulation
list.reverse();
list.sort();
list.clear();
// Length
long size = list.len();
// Operations
py::List combined = list + py::List{9, 10};
list += py::List{11, 12};
py::List repeated = list * 3;py::Tuple tup = {1, 2, 3, "hello"};
// Access (read-only)
py::PyObj item = tup[0];
long len = tup.len();
// Search
long idx = tup.index(2);
long count = tup.count(1);
bool has = tup.contains("hello");
// Operations
py::Tuple combined = tup + py::Tuple{4, 5};
py::Tuple repeated = tup * 2;
// Conversion
py::List as_list = tup.to_list();py::Set set = {1, 2, 3, 3, 2, 1}; // {1, 2, 3}
// Modification
set.add(4);
py::PyObj popped = set.pop();
set.clear();
// Properties
long size = set.len();
bool empty = set.empty();
bool has = set.contains(2);
// Set operations
py::Set a = {1, 2, 3};
py::Set b = {2, 3, 4};
py::Set un = a | b; // Union: {1, 2, 3, 4}
py::Set inter = a & b; // Intersection: {2, 3}
py::Set diff = a - b; // Difference: {1}
py::Set sym = a ^ b; // Symmetric difference: {1, 4}
// In-place
a |= b; // a becomes union
a &= b; // a becomes intersection
a -= b; // a becomes difference
a ^= b; // a becomes symmetric difference
// Subset/superset
bool is_sub = a.issubset(b);
bool is_super = a.issuperset(b);// Construction
py::Dict dict = {
{"name", "Alice"},
{"age", 30},
{"scores", py::List{95, 87, 92}}
};
// Access
py::PyObj name = dict["name"];
py::PyObj age = dict.get("age");
// Modification
dict["city"] = "New York";
dict.set("country", "USA");
py::PyObj removed = dict.pop("age");
// Properties
size_t size = dict.len();
bool empty = dict.empty();
bool has = dict.contains("name");
// Views
py::List keys = dict.keys(); // ["name", "scores", "city", "country"]
py::List values = dict.values(); // ["Alice", [...], "New York", "USA"]
py::List items = dict.items(); // [("name", "Alice"), ...]
// Merging
py::Dict other = {{"email", "[email protected]"}};
dict.update(other);
py::Dict merged = dict | other;
dict |= other;
py::Dict sum_dict = dict + other;
dict += other;
// Clear
dict.clear();// From Python builtins
py::Function print = py::eval("print");
py::Function len = py::eval("len");
py::Function sorted = py::eval("sorted");
// Calling with positional arguments
print("Hello", "World", 42);
// Calling with keyword arguments
py::Dict kwargs = {{"sep", "-"}, {"end", "!\n"}};
print("A", "B", "C", kwargs); // A-B-C!
// Using operator()
py::List list = {3, 1, 4, 1, 5};
py::List result = sorted(list);
long length = len(list);
// Custom Python function from string
py::Function add = py::eval("lambda x, y: x + y");
py::PyObj sum = add(10, 20); // 30py::List data = {1, 2, 3};
py::print(data); // [1, 2, 3]
py::pprint(data); // [
// 1,
// 2,
// 3
// ]py::List list = {3, 1, 4, 1, 5};
long length = py::len(list); // 5
py::Str type_name = py::type(list); // "list"
py::List sorted_list = py::sorted(list); // [1, 1, 3, 4, 5]
py::List reversed_list = py::reversed(list); // [5, 1, 4, 1, 3]py::List all_true = {1, 2, 3};
py::List some_false = {1, 0, 3};
bool a = py::all(all_true); // true
bool b = py::all(some_false); // false
bool c = py::any(some_false); // truepy::Function square = py::eval("lambda x: x ** 2");
py::List numbers = {1, 2, 3, 4, 5};
py::List squared = py::map(square, numbers); // [1, 4, 9, 16, 25]// Execute Python code
py::exec(R"(
def greet(name):
return f"Hello, {name}!"
)");
// Evaluate expression
py::PyObj result = py::eval("greet('World')");
py::print(result); // Hello, World!
// Run Python file
py::run_file("script.py");
// Run file and get globals
py::PyObj globals = py::run_file_result("script.py");
py::Function my_func = globals["my_function"];
my_func();// Python object to JSON string
py::Dict data = {
{"name", "Alice"},
{"age", 30},
{"hobbies", py::List{"reading", "coding"}}
};
std::string json_str = py::json_dumps(data).str();
// {"name": "Alice", "age": 30, "hobbies": ["reading", "coding"]}
// Write to file
py::json_dump(data, "output.json", 4); // 4 spaces indent
// Read from file
py::PyObj loaded = py::json_load("output.json");
// Parse JSON string
py::PyObj parsed = py::json_loads(json_str);#include "pyobj.h"
#include <iostream>
int main() {
py::init_python();
// Import random module
py::exec("import random");
py::Function random = py::eval("random.random");
py::Function randint = py::eval("random.randint");
py::Function choice = py::eval("random.choice");
// Generate random numbers
std::cout << "Random float: " << random() << std::endl;
std::cout << "Random int 1-100: " << randint(1, 100) << std::endl;
// Random choice from list
py::List options = {"apple", "banana", "cherry"};
std::cout << "Random fruit: " << choice(options) << std::endl;
py::exit_python();
return 0;
}py::init_python();
// Create complex nested structure
py::Dict person = {
{"name", "Bob"},
{"age", 25},
{"address", py::Dict{
{"street", "123 Main St"},
{"city", "Boston"},
{"zip", "02101"}
}},
{"hobbies", py::List{"gaming", "hiking", "photography"}}
};
// Access nested data
py::Str city = person["address"]["city"];
std::cout << "City: " << city << std::endl;
// Modify nested data
person["address"]["zip"] = "02102";
person["hobbies"].append("coding");
// Iterate over hobbies
py::List hobbies = person["hobbies"];
for (long i = 0; i < hobbies.len(); ++i) {
std::cout << "Hobby " << i << ": " << hobbies[i] << std::endl;
}
// Pretty print entire structure
py::pprint(person);
py::exit_python();py::init_python();
// Import requests (must be installed)
try {
py::exec("import requests");
py::Function get = py::eval("requests.get");
// Make HTTP request
py::PyObj response = get("https://api.github.com/users/octocat");
// Parse JSON response
py::Dict data = response["json"]();
std::cout << "User: " << data["login"] << std::endl;
std::cout << "Name: " << data["name"] << std::endl;
std::cout << "Repos: " << data["public_repos"] << std::endl;
} catch (...) {
std::cerr << "Failed to import requests" << std::endl;
}
py::exit_python();// Named arguments
std::string msg1 = py::fstring(
"User {name} is {age} years old.",
py::farg("name", "Charlie"),
py::farg("age", 28)
);
// "User Charlie is 28 years old."
// Positional arguments
std::string msg2 = py::fstring(
"Coordinates: ({}, {}, {})",
10, 20, 30
);
// "Coordinates: (10, 20, 30)"
// Mixed arguments
std::string msg3 = py::fstring(
"{greeting} {name}! Your score is {}.",
py::farg("greeting", "Hello"),
py::farg("name", "David"),
95
);
// "Hello David! Your score is 95."
// Escaped braces
std::string msg4 = py::fstring("Set: {{ {} }}", 42);
// "Set: { 42 }"py::init_python();
// Define Python function
py::exec(R"(
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
)");
// Get function
py::Function fib = py::eval("fibonacci");
// Call from C++
for (int i = 0; i < 10; ++i) {
py::PyObj result = fib(i);
std::cout << "fib(" << i << ") = " << result << std::endl;
}
py::exit_python();py::init_python();
// Function with kwargs
py::exec(R"(
def describe_person(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
)");
py::Function describe = py::eval("describe_person");
// Call with Dict as kwargs
py::Dict kwargs = {
{"name", "Eve"},
{"age", 22},
{"city", "London"},
{"occupation", "Engineer"}
};
describe(kwargs);
// Output:
// name: Eve
// age: 22
// city: London
// occupation: Engineer
py::exit_python();| Requirement | Version | Notes |
|---|---|---|
| C++ Compiler | C++17+ | GCC 7+, Clang 5+, MSVC 2017+ |
| Python Development Headers | 3.x | python3-dev or python3-devel |
| Python Library | 3.x | libpython3.x |
# Debian/Ubuntu
sudo apt install python3-dev
# RHEL/CentOS/Fedora
sudo dnf install python3-devel
# Arch
sudo pacman -S python
# macOS (Homebrew)
brew install python@3# Get flags automatically
g++ -std=c++17 main.cpp -o main $(python3-config --includes --ldflags)
# Or manually
g++ -std=c++17 main.cpp -o main \
-I/usr/include/python3.x \
-lpython3.xpyobj.h — это header-only библиотека C++, которая предоставляет Python-подобный синтаксис для встраивания Python в C++ приложения.
Нативный Python C API многословен и подвержен ошибкам:
// Традиционный Python C API — боль!
PyObject* list = PyList_New(0);
PyList_Append(list, PyLong_FromLong(42));
PyObject* item = PyList_GetItem(list, 0);
long value = PyLong_AsLong(item);
Py_DECREF(item);
Py_DECREF(list);С pyobj.h — чисто и интуитивно:
// pyobj.h — пишется как Python!
py::List list;
list.append(42);
long value = list[0]; // Автоматическая конвертация!| Класс | Python-эквивалент | Ключевые методы |
|---|---|---|
py::PyObj |
object |
Базовый класс, operator[], operator(), str(), is_*() |
py::Str |
str |
upper(), lower(), split(), join(), find(), replace() |
py::List |
list |
append(), pop(), extend(), sort(), reverse(), index() |
py::Tuple |
tuple |
index(), count(), to_list(), operator[] |
py::Set |
set |
add(), pop(), union_with(), intersection(), difference() |
py::Dict |
dict |
get(), set(), pop(), keys(), values(), items(), update() |
py::Function |
callable |
call(), operator() с поддержкой kwargs |
| Функция | Python-эквивалент | Описание |
|---|---|---|
py::print(obj) |
print() |
Печать любого Python-объекта |
py::pprint(obj) |
pprint.pprint() |
Красивая печать с отступами |
py::len(obj) |
len() |
Длина последовательности/коллекции |
py::type(obj) |
type() |
Имя типа в виде строки |
py::sorted(seq) |
sorted() |
Отсортированный список |
py::reversed(obj) |
reversed() |
Обратная последовательность |
py::all(list) |
all() |
True если все элементы истинны |
py::any(list) |
any() |
True если хотя бы один элемент истинен |
py::map(func, list) |
map() |
Применить функцию к каждому элементу |
py::exec(code) |
exec() |
Выполнить строку кода Python |
py::eval(code) |
eval() |
Вычислить выражение Python |
py::run_file(path) |
exec(open().read()) |
Выполнить файл Python |
Header-only библиотека — просто скопируй pyobj.h в проект!
wget https://raw.githubusercontent.com/vk-candpython/pyobj/main/pyobj.hg++ -std=c++17 main.cpp -o main $(python3-config --includes --ldflags)#include "pyobj.h"
int main() {
py::init_python();
py::List my_list = {1, 2, 3, "hello"};
my_list.append(42);
py::print(my_list); // [1, 2, 3, 'hello', 42]
py::exit_python();
return 0;
}(См. английскую версию для подробного API каждого класса)
py::init_python();
py::exec("import random");
py::Function randint = py::eval("random.randint");
std::cout << "Случайное число 1-100: " << randint(1, 100) << std::endl;
py::exit_python();py::init_python();
py::Dict person = {
{"name", "Alice"},
{"age", 30},
{"hobbies", py::List{"reading", "coding"}}
};
py::Str name = person["name"];
person["age"] = 31;
person["hobbies"].append("gaming");
py::pprint(person);
py::exit_python();| Требование | Версия | Примечания |
|---|---|---|
| Компилятор C++ | C++17+ | GCC 7+, Clang 5+, MSVC 2017+ |
| Python Development Headers | 3.x | python3-dev или python3-devel |
# Установка в Ubuntu/Debian
sudo apt install python3-dev
# Компиляция
g++ -std=c++17 main.cpp -o main $(python3-config --includes --ldflags)Python in C++ — As Easy as Python Itself