boost :: python :: class:以编程方式获取类名

eud*_*xos 0 visitor boost-python

我使用模板化的游标来为几个类定义统一的接口.为了定义__str____repr__方法,我想以编程方式"X"boost::python::class对象中获取类名(在引用文档中).那可能吗?

通过将类名作为参数传递给访问者的构造函数,可以很容易地处理它,但自动拥有它会更优雅.

Tan*_*ury 5

boost::python::class_派生自boost::python::object,因此可以__name__从类对象中查询属性.

这是一个简单的例子:

#include <boost/python.hpp>

class X {};

BOOST_PYTHON_MODULE(example)
{ 
  namespace python = boost::python;
  python::object x_class = python::class_<X>("X");

  // Extract the class' __name__ attribute, printing whatever was passed to
  // class_ constructor.
  std::cout << boost::python::extract<std::string>(x_class.attr("__name__"))()
            << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

并输出:

>>> import example
X
Run Code Online (Sandbox Code Playgroud)

为了扩展这种方法,来自的访问者boost::python::def_visitor需要:

  • 定义 __str__和/或__repr__作为一般通过返回boost::python::object"类"名称的函数o.__class__.__name__.
  • 提取并存储类名,然后定义 __str__和/或__repr__作为访问存储值的函数.

以下示例演示了这两种方法.

#include <boost/python.hpp>

/// @brief Helper type used to set and get a boost::python::class_
///        object's type name.
template <typename ClassT>
class typed_class_name
{
public:
  /// @brief Extract and store the __name__ from a 
  ///        boost::python::class_ objct.
  static void set(const ClassT& c)
  {
    name_ = boost::python::extract<std::string>(c.attr("__name__"));
  }

  /// @brief Return the stored name.
  static std::string get(const typename ClassT::wrapped_type&)
  {
    std::cout << "typed" << std::endl;
    return name_;
  }
private:
  static std::string name_;
};

template <typename ClassT> std::string typed_class_name<ClassT>::name_;

/// @brief Generically get a python object's class name. 
struct generic_class_name
{
  static boost::python::object get(const boost::python::object& self)
  {
    std::cout << "generic" << std::endl;
    return self.attr("__class__").attr("__name__");
  }
};

class my_def_visitor
  : public boost::python::def_visitor<my_def_visitor>
{
  friend class boost::python::def_visitor_access;

  template <class ClassT>
  void visit(ClassT& c) const
  {
    // Store the class name.
    typed_class_name<ClassT>::set(c);

    c 
      .def("__str__",  &typed_class_name<ClassT>::get) // typed
      .def("__repr__", &generic_class_name::get)       // generic
      ;
  }
};

class X {};

BOOST_PYTHON_MODULE(example)
{ 
  namespace python = boost::python;
  python::class_<X>("X")
    .def(my_def_visitor())
    ;
}
Run Code Online (Sandbox Code Playgroud)

用法:

>>> import example
>>> x = example.X()
>>> str(x)
typed
'X'
>>> repr(x)
generic
'X'
Run Code Online (Sandbox Code Playgroud)