[QUESTION] Returning a Python built-in type #4249
-
I have a C++ enum that I use to keep track of some value types: enum class ValueType {
INT32 = 0,
FLOAT,
DOUBLE,
BOOL,
STR,
}; which is bound as such: py::enum_<ValueType>(m, "ValueType", "List all types available")
.value("INT32", ValueType::INT32, "int32_t type")
.value("FLOAT", ValueType::FLOAT, "float type")
.value("DOUBLE", ValueType::DOUBLE, "double type")
.value("BOOL", ValueType::BOOL, "bool type")
.value("STR", ValueType::STR, "string type"); Now, if I want to retrieve the matching Python type, I need (in Python) something along the lines of: from my_cpp_module import ValueType
def type_from_value_type(value_type: ValueType):
if value_type is ValueType.INT32:
return int
elif value_type in [ValueType.FLOAT, ValueType.DOUBLE]:
return float
elif value_type is ValueType.BOOL:
return bool
elif value_type is ValueType.STR:
return str
else:
return None Is there any way to move this code in the binding instead? I've done some research in about My desired usage would be something like this: from my_cpp_module import ValueType, type_from_value_type
# Example of implementation as property 'type'
assert ValueType.INT32.type == int # True
# Example of implementation as an internal method 'type()'
assert ValueType.INT32.type() == int # True
# Example of implementation as a separate method 'type_from_value_type()'
assert type_from_value_type(ValueType.INT32) == int # True |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
First things first, without helper function it is impossible to translate enum values (which are in fact integers) to some types. This is a good point from you that you need some helper either in form of separate method or How to approach this? Why don't use wrapper classes for this? "Fake it till you make it" -- this is the general idea. First create a class that will simulate single enum entry, let's call it (Disclaimer: I am pretty aware that it might not be an optimal and the cleanest solution but it gets work done. I will leave refactoring and improvements to you:) One thing is to hide helper I hope that my explenation helps and provide some ideas for further improvements, cheers! enum class ValueType
{
INT32 = 0,
FLOAT,
};
// Wrapping code starts here
namespace py = pybind11;
class ValueTypeWrapper
{
public:
ValueTypeWrapper(ValueType value, py::object type_obj) : m_value{value}, m_type_obj{type_obj}
{
}
ValueType m_value;
py::object m_type_obj;
};
struct FakeEnum
{
inline static const ValueTypeWrapper INT32 = ValueTypeWrapper(ValueType::INT32, py::int_());
inline static const ValueTypeWrapper FLOAT = ValueTypeWrapper(ValueType::FLOAT, py::float_());
};
PYBIND11_MODULE(mymodule, m)
{
py::class_<ValueTypeWrapper> v(m, "ValueTypeWrapper");
v.def(py::init<ValueType, py::object>());
v.def("__eq__", [](ValueTypeWrapper &self, ValueTypeWrapper &other)
{ return self.m_value == other.m_value; });
v.def("__repr__", [](ValueTypeWrapper &self)
{ return "<ValueType: " + std::to_string(static_cast<int>(self.m_value)) + ">"; });
v.def("type", [](ValueTypeWrapper &self)
{ return py::type::of(self.m_type_obj); });
// v.def_property_readonly("type", ...);
py::class_<FakeEnum> f(m, "ValueType", "List all types available");
f.def(py::init<>());
f.def_property_readonly_static("INT32", [](py::object)
{ return FakeEnum::INT32; });
f.def_property_readonly_static("FLOAT", [](py::object)
{ return FakeEnum::FLOAT; });
} Testing: In [2]: import mymodule as m
...:
In [3]: a = m.ValueType.INT32
...:
In [4]: a
Out[4]: <ValueType: 0>
In [5]: a is int
Out[5]: False
In [6]: a.type() is int
Out[6]: True
In [7]: m.ValueType.FLOAT.type() is float
Out[7]: True
In [8]: m.ValueType.FLOAT.type() is int
Out[8]: False
In [11]: def type_from_value_type(value_type: m.ValueType):
...: # small modification to use `__eq__` from `is` -> `==`
...: if value_type == m.ValueType.INT32:
...: return int
...: elif value_type == m.ValueType.FLOAT:
...: return float
...: else:
...: return None
...:
In [12]: type_from_value_type(m.ValueType.INT32) == int
Out[12]: True
In [15]: # I think this is better solution overall
...: def type_from_value_type(value_type: m.ValueType):
...: return value_type.type()
...:
In [16]: type_from_value_type(m.ValueType.INT32) == int
...:
Out[16]: True |
Beta Was this translation helpful? Give feedback.
First things first, without helper function it is impossible to translate enum values (which are in fact integers) to some types. This is a good point from you that you need some helper either in form of separate method or
type/type()
.How to approach this? Why don't use wrapper classes for this? "Fake it till you make it" -- this is the general idea. First create a class that will simulate single enum entry, let's call it
ValueTypeWrapper
. It will hold two values, actual integer value from enum andpy::object
(it will be useful later). CreateFakeEnum
struct that will be inserted in place of ValueType, still look at the name when binding -- it matches original one. Now define essential h…