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
|