[Python] How to bind a Singleton to Python in pybind across libraries

Discussão em 'Python' iniciado por Stack, Julho 25, 2025.

  1. Stack

    Stack Membro Participativo

    I have a Singleton defined in C++ that I want to expose to Python. Python seems to create a new instance of the Singleton no matter how I bind it. My main code is in a core library, which the Python module is also linked to.

    cmake_minimum_required(VERSION 3.12)
    project(pybind-singleton)

    cmake_policy(SET CMP0148 NEW)
    set(CMAKE_CXX_STANDARD 17)

    find_package(pybind11 CONFIG REQUIRED)
    find_package(Python3 COMPONENTS Interpreter Development REQUIRED)

    add_library(my_lib SHARED
    src/Singleton.cpp
    )

    message(STATUS "Python include dirs: " ${PYTHON_INCLUDE_DIRS})
    message(STATUS "pybind include dirs: " ${pybind11_INCLUDE_DIRS})
    target_include_directories(my_lib PUBLIC include ${PYTHON_INCLUDE_DIRS} ${pybind11_INCLUDE_DIRS})
    target_link_libraries(my_lib PUBLIC Python3::python)

    pybind11_add_module(my_module src/binding.cpp)
    target_link_libraries(my_module PUBLIC my_lib)


    add_executable(${CMAKE_PROJECT_NAME} src/main.cpp)
    target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC my_lib)


    class Singleton
    {
    public:
    static Singleton &GetInstance()
    {
    static Singleton instance;
    return instance;
    }

    Singleton(Singleton const &) = delete;
    void operator=(Singleton const &) = delete;
    std::string test;

    void Init();

    void PrintTest();

    private:
    Singleton(){};
    };



    namespace py = pybind11;

    PYBIND11_MODULE(my_module, m)
    {
    py::class_<Singleton>(m, "Singleton")
    .def_static(
    "print_test", []()
    { Singleton::GetInstance().PrintTest(); },
    py::return_value_policy::reference)
    .def_static(
    "get_test_val", []()
    {
    Singleton &singleton = Singleton::GetInstance();
    return singleton.test; },
    py::return_value_policy::reference)
    .def_static(
    "get_instance", &Singleton::GetInstance, py::return_value_policy::reference)
    .def_readwrite("test", &Singleton::test);
    }


    from my_module import Singleton

    print('Accessing Singleton...')

    test_val = Singleton.get_test_val()
    print('Test val:', test_val if test_val != '' else 'None')

    print('--')
    Singleton.print_test()

    print('--')
    instance = Singleton.get_instance()
    print(instance)
    print(instance.test)
    instance.test = 'Python\'s instance'
    print(instance.test)
    instance.print_test()


    % ./pybind-singleton
    Instancing Singleton...
    /Users/jordan/dev/pybind-singleton/src/Singleton.cpp: 12

    /Users/jordan/dev/pybind-singleton/src/Singleton.cpp: 12
    C++'s instance
    ------------
    Running init.py
    Accessing Singleton...
    Test val: None
    --
    /Users/jordan/dev/pybind-singleton/src/Singleton.cpp: 12

    --
    <my_module.Singleton object at 0x1024b9fb0>

    Python's instance
    /Users/jordan/dev/pybind-singleton/src/Singleton.cpp: 12
    Python's instance


    I've made up a minimal example in this repo; some of the code has been omitted from above for brevity: https://github.com/jordanlevy96/pybind-singleton

    Continue reading...

Compartilhe esta Página