[C++-sig] how to override __setattr__ of an extension class

Wojciech Mamrak wmamrak at gmail.com
Tue Feb 28 21:57:41 CET 2012


Yes, this is what I meant :)

I will precise my previous message. The docs are very concise on some
topics, hence misleading.
If you find such statement:
"Beware the common pitfall of forgetting that the constructors of most
of Python's mutable types make copies, just as in Python."

then it is confusing why:

		dict a;
		dict b = dict(a); //copy? in Python yes, here not
		b["key"] = 1;
		(a.has_key("key")) ? puts("KEY FOUND") : puts("KEY NOT FOUND"); //KEY FOUND

yields KEY FOUND, opposite to its Python equivalent (posted earlier).

But the docs are correct, since they provide more or less such
exemplary (and different) code:

		object x = import("__main__");
		dict a(x.attr("__dict__")); //copy
		dict b = extract<dict>(x.attr("__dict__")); //no copy
		x.attr("__dict__")["key"] = 1;
		(a.has_key("key")) ? puts("KEY FOUND") : puts("KEY NOT FOUND");
//KEY NOT FOUND
		(b.has_key("key")) ? puts("KEY FOUND") : puts("KEY NOT FOUND"); //KEY FOUND


regards





2012/2/28 Holger Joukl <Holger.Joukl at lbbw.de>:
> 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
>
> _______________________________________________
> Cplusplus-sig mailing list
> Cplusplus-sig at python.org
> http://mail.python.org/mailman/listinfo/cplusplus-sig


More information about the Cplusplus-sig mailing list