2

を使用して、いくつかの仮想関数を持つboost::pythonクラス()をラップすることができましたNode。これは大変なことでしたが、現在はクラスをオーバーライドしようとしていますsetattr/getattr。自分の実装boost::pythonを呼び出すsetattr必要がありますが、発生する再帰を回避する方法がわかりません。

だから私はNodeクラスを持っています、そして私は書くことができるようになりたいです:

node1.param1 = 5          # Call node.SetParam
node1.plain_member = 7    # Call object.__setattr__

これまでのところ、私は(非常に要約して)持っています:

namespace bpy = boost::python;

struct NodeWrap : vcNode, bpy::wrapper<Node> {
  ...  
  static void setattr(bpy::object obj, std::string attr, bpy::object val)
  {
     NodeWrap const& node = bpy::extract<NodeWrap const&>(obj)();
     ParamRef p = node.FindParam(attr);
     if (p)
        py_to_param(p, val); //This part works fine
     else
     {
        obj.attr(attr) = val; //Problematic line - recurses indefinitely
     }
  }
};

次に、BOOST_PYTHON_MODULEセクションで、私は持っています:

bpy::class_<NodeWrap, boost::shared_ptr<NodeWrap>, boost::noncopyable>("Node")
  ...
  .def("__setattr__". &NodeWrap::setattr);

私が言ったように、それはうまくコンパイルされ、ノードの「params」を正しく設定しますが、そのような非paramを設定しようとするとself.plain_old_member = 7、「Recursion Depth Exceeded」エラーが発生します。これは、収集boost::object::attrするとクラスが呼び出されるためです。 '__setattr__メソッド

Pythonでは、次を使用してこれを回避します

super(Node).__setattr__(self, attr, val)

問題の行にありますが、boost::pythonからそれを行う方法を理解できません。必要に応じてCAPIにアクセスしてもかまいませんが(実際、PyObject_SetAttrString無駄に使用してみました)、ここからアクセスする方法がわかりません。

乾杯、マット

4

1 に答える 1

1

必要なPythonC-API関数はPyObject_GenericSetAttr;だと思います。つまり、「問題のある行」を次のように置き換える必要があります。

bpy::str attr_str(attr);
if (PyObject_GenericSetAttr(obj.ptr(), attr_str.ptr(), val.ptr()) != 0)
    bpy::throw_error_already_set();

これはPythonで呼び出すのと同じだと思います。これは基本クラスobject.__setattr__(self, attr, val)を呼び出すのと同じではありません__setattr__が、違いは基本クラスもオーバーライドする場合にのみ重要です__setattr__。その場合は、次のようなことを行う必要があります。

bpy::object cls(bpy::handle<>(PyObject_Type(obj.ptr())));
bpy::object base_cls = cls.attr("__bases__")[0];
base_cls.attr("__setattr__")(obj, attr, val);
于 2012-05-23T01:42:01.743 に答える