2012-05-22 23 views
2

使用boost::python,我已經能夠包裝一個具有一些虛擬功能的類(Node),並且它是一個叫聲,但現在我試圖覆蓋該類的setattr/getattr。 我有boost::python打電話給我自己的setattr實現,但我無法弄清楚如何避免發生遞歸。如何覆蓋包裝類中的__setattr__(來自C++)?

所以我有一個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); 

正如我所說的,它編譯得很好,並將設置任何節點「第MS」正確的,但如果我嘗試設置非PARAM,如self.plain_old_member = 7然後我得到一個‘遞歸深度超出’的錯誤,因爲我收集boost::object::attr將調用類__setattr__方法

在Python中,我會得到通過使用

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

在問題行中,但我無法弄清楚如何從boost :: python做到這一點。 我不介意去C API,如果我必須(實際上,我試過使用PyObject_SetAttrString無濟於事),但我只是不知道如何從這裏到達那裏。

乾杯, 馬特

回答

1

我相信你想要的Python的C-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,這是不一樣的基類調用__setattr__object.__setattr__(self, attr, val),但不同的事項,如果一個基類也會覆蓋__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); 
+0

太棒了!我發現了一個緩慢而醜陋的解決方法(使用'bpy :: exec(「object .__ setattr __(obj,attr,val)」...',每次都需要填充字典和抓取__main __.__ dict__)。 – Gretchen