Re: [PyGiNaC-users] Python lists of GiNaC objects?
Status: Alpha
Brought to you by:
jbrandmeyer
From: Jonathan B. <jbr...@ea...> - 2005-09-14 23:10:36
|
On Wed, 2005-09-14 at 23:55 +0200, Richard B. Kreckel wrote: > Hi, > > I've just tried to hack a continued fraction routine into PyGiNaC: > > diff -r1.7 numeric.cpp > 17a18 > > #include <cln/real.h> > 111a113,146 For cleanliness, you probably just want to return a boost::python::object... > > static PyObject* > > do_contfrac(const GiNaC::numeric x, unsigned len) > > { > > boost::python::list result; > > if (!x.is_real()) { > > // Complex? > > Py_INCREF(result.ptr()); > > return result.ptr(); which makes this statement "return result;" without the Py_INCREF business. > > } > > cln::cl_R x_ = cln::the<cln::cl_R>(x.to_cl_N()); > > bool negative = false; > > if (cln::minusp(x_)) { > > negative = true; > > x_ = -x_; > > } > > for (unsigned r=0; r<len; ++r) { > > // Split x into integral and fractional part. > > cln::cl_R_div_t x_split = cln::floor2(x_); > > if (negative) { > > result.append(boost::python::object(GiNaC::ex(-GiNaC::numeric(x_split.quotient)))); The ex will be automatically converted back to a numeric when wrapping it as an object, and list::append() automatically attempts to wrap/convert any argument it gets in/to a Python object, so just use result.append( -GiNaC::numeric(x_split.quotient)); > > negative = false; > > } else { > > result.append(boost::python::object(GiNaC::ex(GiNaC::numeric(x_split.quotient)))); Same here. > > } > > x_ = x_split.remainder; > > if (cln::zerop(x_)) > > break; > > // Invert x. > > x_ = cln::recip(x_); > > } > > Py_INCREF(result.ptr()); > > return result.ptr(); Again, you don't need to do this. Just "return result;" and allow class boost::python::object to manage the refcount. If you saw manual refcount management in the PyGiNaC code it should be limited to the custom rvalue converter registration code. In general, you can just rely on class object's automatic refcount management. > > } > > > 156a192 > > def( "contfrac", &do_contfrac, "continued fraction of a real number."); > > However, when I use it: > > >>> l=contfrac(3.1415926,2) > >>> print l > [<cginac.numeric object at 0xb7dbf974>, <cginac.numeric object at 0xb7dbf9bc>] This is because 'l' is actually a Python list, it isn't a GiNaC::exlist (sp?) pretending to be a Python list. The python list's __str__ method (invoked by the print statement) annoyingly invokes the __repr__ method of its containees rather than __str__. __repr__ isn't defined by PyGiNaC's classes, so you get the default behavior: the address of the wrapping PyObject. There are (at least) two workarounds. You can force conversion to a string every time you want to display the members when at print time with a list comprehension. You can modify the definition of class 'basic' (at runtime!) such that it has a non-default __repr__ method. Python 2.3.5 (#2, Aug 30 2005, 15:50:26) [GCC 4.0.2 20050821 (prerelease) (Debian 4.0.1-6)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from ginac import * >>> l = [numeric(1), numeric(3)] >>> isinstance(l, list) True >>> print l [<cginac.numeric object at 0xb7d25c84>, <cginac.numeric object at 0xb7d34c34>] >>> print [str(x) for x in l] # so-called "list comprehension" ['1.0', '3.0'] >>> # Change the definition of class cginac.basic >>> basic.__repr__ = basic.__str__ >>> print l [1.0, 3.0] >>> del basic.__repr__ # Restore default behavior >>> print l [<cginac.numeric object at 0xb7d25c84>, <cginac.numeric object at 0xb7d34c34>] HTH, -Jonathan |