问题
Using boost::python
, I have been able to wrap a class (Node
) which has some virtual functions, and it's been a hoot, but now I'm trying to override setattr/getattr
for the class.
I've got boost::python
to call my own setattr
implementation, but I can't figure out how to avoid the recursion that happens.
So I have a Node
class, and I want to be able to write:
node1.param1 = 5 # Call node.SetParam
node1.plain_member = 7 # Call object.__setattr__
So far, I have (very abridged):
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
}
}
};
then in the BOOST_PYTHON_MODULE
section, I have:
bpy::class_<NodeWrap, boost::shared_ptr<NodeWrap>, boost::noncopyable>("Node")
...
.def("__setattr__". &NodeWrap::setattr);
As I said, it compiles just fine, and will set any node "params" correctly, but if I try to set a non-param, such as self.plain_old_member = 7
then I get a "Recursion Depth Exceeded" error, because I gather boost::object::attr
will call the class' __setattr__
method
In python, I would get around this by using
super(Node).__setattr__(self, attr, val)
in the problem line, but I can't figure out how to do that from boost::python.
I don't mind going to the C API if I have to (in fact, I've tried using PyObject_SetAttrString
to no avail), but I just don't know how to get there from here.
Cheers, Matt
回答1:
I believe the Python C-API function you want is PyObject_GenericSetAttr
; that is, you should replace the "problematic line" with:
bpy::str attr_str(attr);
if (PyObject_GenericSetAttr(obj.ptr(), attr_str.ptr(), val.ptr()) != 0)
bpy::throw_error_already_set();
I think this is equivalent to calling object.__setattr__(self, attr, val)
in Python, which is not the same as calling __setattr__
on a base class, but the difference only matters if a base class also overrides __setattr__
. If that's the case, you'd need to do something like this:
bpy::object cls(bpy::handle<>(PyObject_Type(obj.ptr())));
bpy::object base_cls = cls.attr("__bases__")[0];
base_cls.attr("__setattr__")(obj, attr, val);
来源:https://stackoverflow.com/questions/10694367/how-to-override-setattr-in-a-wrapped-class-from-c