pybind11: passing named arguments

pybind11 allow us to expose c++ class/function to higher abstraction level of python programming language, bringing high performance and flexibility into python.

To pass named arguments in python, it’s required to specify argument names in pybind11’s interface. In this post, I will illustrate how to do that.

c++ class

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <pybind11/pybind11.h>
#include <pybind11/embed.h>
#include <pybind11/stl.h>
#include <iostream>
#include <cstdlib>
#include <cstdio>

// from SnailCore
#include <util/acct_info.hpp>
#include <util/shm.hpp>
#include <util/shm_tool.hpp>
#include <util/shm_status.hpp>
#include <util/shm_struct.hpp>
#include <util/shmv.hpp>
#include <util/time_util.hpp>
#include <util/index_type.hpp>
#include <util/str_util.hpp>

function

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
py::dict pybind11_read_shm_acc(const std::string& shm_tag)
{
    std::unique_ptr<snail::acct_info_t::shm_reader_t> reader {new snail::acct_info_t::shm_reader_t(shm_tag)};

    auto total = reader->size();
    std::cout << "total:" << total << std::endl;

    std::vector<std::string> client_id, us;
    std::vector<double> beg_balance, curr_balance, enabled_balance,
                        frozen_balance, deposit, margin, frozen_margin,
                        fee, frozen_fee, pos_profit, close_profit;

    for (size_t i = 0; i < total; ++i)
    {
        auto e = reader->safe_get(i);

        client_id.emplace_back(e->client_id);
        us.emplace_back(microtime::from_count(e->us).to_zgc_str());

        beg_balance.emplace_back(e->beg_balance);
        curr_balance.emplace_back(e->curr_balance);
        enabled_balance.emplace_back(e->enabled_balance);
        frozen_balance.emplace_back(e->frozen_balance);
        deposit.emplace_back(e->deposit);
        margin.emplace_back(e->margin);
        frozen_margin.emplace_back(e->frozen_margin);
        fee.emplace_back(e->fee);
        frozen_fee.emplace_back(e->frozen_fee);
        pos_profit.emplace_back(e->pos_profit);
        close_profit.emplace_back(e->close_profit);
    }

    py::dict d;
    d["US"] = us;
    d["ClientID"] = client_id;
    d["BegBalance"] = beg_balance;
    d["CurrBalance"] = curr_balance;
    d["EnabledBalance"] = enabled_balance;

    d["FrozenBalance"] = frozen_balance;
    d["Deposit"] = deposit;
    d["Margin"] = margin;
    d["FrozenMargin"] = frozen_margin;
    d["Fee"] = fee;
    d["FrozenFee"] = frozen_fee;
    d["PosProfit"] = pos_profit;
    d["CloseProfit"] = close_profit;

    return d;
}

class

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class Account
{
public:
    Account(const std::string& shm_tag, int shm_size, bool continued = false)
        : _shm_tag{shm_tag}
        , _shm_size{shm_size}
        , _continued{false}
    {
        _shm_acc.reset(new acct_info_t::shm_writer_t(
            _shm_tag, _shm_size, _continued
            ));
    }

    ~Account()
    {}

    void write(const std::string& client_id,
               double beg_balance,
               double curr_balance,
               double enabled_balance,
               double frozen_balance = 0.0,
               double deposit = 0.0,
               double margin = 0.0,
               double frozen_margin = 0.0,
               double fee = 0.0,
               double frozen_fee = 0.0,
               double pos_profit = 0.0,
               double close_profit = 0.0,
               uint64_t us = 0
               )
    {
        auto e = _shm_acc->get_slot();
        if (!e)
        {
            std::cout << "failed to get_slot, shm is full" << std::endl;
            return;
        }
        e->us = us == 0 ? microtime::now().count(): us;
        copy_str(e->client_id, client_id.c_str());

        e->beg_balance = beg_balance;
        e->curr_balance = curr_balance;
        e->enabled_balance = enabled_balance;

        e->frozen_balance = frozen_balance;
        e->deposit = deposit;
        e->margin = margin;
        e->frozen_margin = frozen_margin;
        e->fee = fee;
        e->frozen_fee = frozen_fee;
        e->pos_profit = pos_profit;
        e->close_profit = close_profit;

        _shm_acc->commit(e);
    }

    py::dict read()
    {
        return pybind11_read_shm_acc(_shm_tag);
    }

private:
    std::string _shm_tag;
    int _shm_size {0};
    bool _continued {false};
    std::shared_ptr<typename acct_info_t::shm_writer_t> _shm_acc;
};

pybind11 interface

pybind11 provides by MACRO interfaces of c++. By defining py::arg("shm_tag"), it’s possible to pass named arguments from python into c++’s functions/classes, with default values setting.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
PYBIND11_MODULE(snail, m)
{
    // Function Interface
    m.def("pybind11_read_shm_acc", &pybind11_read_shm_acc, R"pbdoc(
        read snail::acct_info_t
    )pbdoc");

    // Class Interface
    // define Account class
    py::class_<Account>(m, "Account")
        // ctor
        .def(py::init<const std::string&, int, bool>(),
             py::arg("shm_tag"),
             py::arg("shm_size"),
             py::arg("continued") = false
             )
        .def("write", &Account::write,
             py::arg("client_id"),
             py::arg("beg_balance"),
             py::arg("curr_balance"),
             py::arg("enabled_balance"),
             py::arg("frozen_balance") = 0.0,
             py::arg("deposit") = 0.0,
             py::arg("margin") = 0.0,
             py::arg("frozen_margin") = 0.0,
             py::arg("fee") = 0.0,
             py::arg("frozen_fee") = 0.0,
             py::arg("pos_profit") = 0.0,
             py::arg("close_profit") = 0.0,
             py::arg("us") = 0
             )
        .def("read", &Account::read)
        ;

#ifdef VERSION_INFO
    m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO);
#else
    m.attr("__version__") = "dev";
#endif
}

python calling

Now we can call c++ functions/class interfaces in python.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
from wepy.cpp.snail import pybind11_read_shm_acc
from wepy.cpp.snail import Account

## Function Interface
def read_shm_acc(shm_tag:str) -> pd.DataFrame:
    data = pybind11_read_shm_acc(shm_tag)
    return pd.DataFrame(data)

## Class Interface
from wepy.cpp.snail import Account
acct = Account(shm_tag = "lfang_acc", shm_size = 1000)
acct.write(client_id = "lfang",
            beg_balance = 1000.0,
            curr_balance = 1000.0,
            enabled_balance = 1000.0,
            deposit = 100)
df = pd.DataFrame(acct.read())
df = read_shm_acc("lfang_acc")

python-calling
python-calling

相关内容

william 支付宝支付宝
william 微信微信
0%