[C++-sig] how to override __setattr__ of an extension class
Holger Joukl
Holger.Joukl at LBBW.de
Tue Feb 28 17:52:46 CET 2012
Hi,
> The docs regarding the mutable copying problem are very misleading.
> Following Python [1] and Boost [2] scripts do not produce the same
results:
>
>
> [1]
> b = a = []
> c = list(a)
> a.append("s1")
> print a.count("s1"), b.count("s1"), c.count("s1") #prints 1 1 0
>
> [2]
> list a, b, c;
> b = a;
> c = list(a);
> a.append("s1");
> list d = extract<list>(a);
> printf("%i %i %i %i\n", a.count("s1"), b.count("s1"), c.count("s1"),
> d.count("s1")); //prints 1 1 1 1
>
> In [2] expected was 1 1 0 1 according to Pythonic behaviour (it states
> in docs that such behaviour is mimicked). This is in conflict with
> example provided in the tutorial.
Ok, so it seems behaviour is different when dealing with
boost::python::object vs
PyObject* as constructor arguments.
Using extract<> to modify mutable objects is only necessary when dealing
with PyObject*:
// boost_dict.cpp
/* build cmdline:
/apps/local/gcc/4.6.1/bin/g++ -g -Wall -R /apps/local/gcc/4.6.1/lib/
-R /var/tmp/boost/gcc/boost_1_47_0/stage/gcc-4.6.1/py2.7/boost/1.47.0/lib/
-L /var/tmp/boost/gcc/boost_1_47_0/stage/gcc-4.6.1/py2.7/boost/1.47.0/lib/
-I /var/tmp/boost/gcc/boost_1_47_0/
-I /apps/local/gcc/4.6.1/include/python2.7/ -L /apps/local/gcc/4.6.1/lib
boost_dict.cpp -lboost_python -lrt -lpython2.7
*/
#include <boost/python.hpp>
#include <iostream>
namespace bp = boost::python;
int main(void) {
// otherwise we core dump
Py_Initialize();
bp::object value(1);
std::cout << "arg is bp::dict:" << std::endl;
{
bp::dict d1, d2, d3;
d2 = d1;
d3 = bp::dict(d1);
d1["k1"] = value;
bp::dict d4 = bp::extract<bp::dict>(d1);
std::cout << d1.has_key("k1")
<< " " << d2.has_key("k1")
<< " " << d3.has_key("k1")
<< " " << d4.has_key("k1") << std::endl;
}
std::cout << std::endl;
std::cout << "arg is bp::handle<(PyObj*)" << std::endl;
{
bp::dict d1, d2, d3;
// must use a handle to feed PyObj* to bp::objects
bp::handle<> dict_pyobj_handle(d1.ptr());
// Note: no operator= for handle<>
d2 = bp::dict(dict_pyobj_handle);
d3 = bp::dict(dict_pyobj_handle);
d1["k1"] = value;
bp::dict d4 = bp::extract<bp::dict>(d1.ptr());
std::cout << d1.has_key("k1")
<< " " << d2.has_key("k1")
<< " " << d3.has_key("k1")
<< " " << d4.has_key("k1") << std::endl;
}
Py_Finalize();
return 0;
}
$ ./a.out
arg is bp::dict:
1 1 1 1
arg is bp::handle<(PyObj*)
1 0 0 1
So I think the tutorial example (if that's what you meant?)
"
C++:
dict d(x.attr("__dict__")); // copies x.__dict__
d['whatever'] = 3; // modifies the copy
"
is pretty subtle, as - if I understand correctly - this
- retrieves an attribute proxy from x
- that returns the bp::object-wrapped __dict__ attribute (which copies the
original PyObject* __dict__)
- constructs d from this new bp::object (which increases the refcount but
doesn't make another copy)
and the assignment operates on this new bp::object.
Regards
Holger
Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart
More information about the Cplusplus-sig
mailing list