0

I am using templated vistors to define unified interface for several classes. For the purposes of definint the __str__ and __repr__ methods, I would like to programatically obtain class name (the "X" in the referenced documentation) from the boost::python::class object. Is that possible?

It is easy to work it around by passing the class name as argument to the visitor's constructor, but having it automatically would be more elegant.

4

1 回答 1

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;
}

和输出:

>>> import example
X

为了扩展这种方法,来自的访问者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())
    ;
}

以及用法:

>>> import example
>>> x = example.X()
>>> str(x)
typed
'X'
>>> repr(x)
generic
'X'
于 2013-07-31T16:22:20.177 回答