Hack request: rational numbers

Pearu Peterson pearu at cens.ioc.ee
Thu Jan 25 11:01:01 EST 2001


Hi!

I am using rational numbers from the gmpy module and I find that creating
one in Python using

>>> mpq(3,4)

is rather clumsy. Clearly, minimal representation of this rational number
is

    3/4

but in Python this expression has different meaning.
So, I am looking for a "nicer" way to create gmpy rational numbers in
Python. Closest to the above representation I find

    3r/4

that uses similar syntax as in constructing Python complex numbers
(cf. 3j+4).

Note that I don't want to implement a new Python rational number type but
rather to use gmpy's mpq number type. So, I am looking for solution
where when using

>>> 3r

in Python (prompt or script),

>>> mpq(3)

is actually executed.

Since `3r' is very similar to `3j', I thought that it would be easy to
hack Python source to read `3r' as a NUMBER and then create
`mpq(3)'. Indeed, I found that one only needs to insert few lines to
the function `parsenumber' in the file Python/compile.c:
	...
	if (*end == 'l' || *end == 'L')
	        return PyLong_FromString(s, (char **)0, 0);
	if (*end == 'r' || *end == 'R') 
	        return (*end='\0', Pygmpy_mpq_FromString(s));
	...

But then the problem is that gmpy needs to be statically linked with
Python. This is not good for several reasons:
1) Also GMP library (not easily available for non-U*NX systems) needs to
be statically linked with python.
2) It is then impossible to use other rational number modules. For
example, it is easy to write one in pure Python.

To overcome this difficulty, I propose using settable rational number
constructor as follows:

>>> from gmpy import mpq
>>> __builtins__._construct_rational = mpq
>>> 3r/4
mpq(3,4)

and modifications in `parsenumber' function would be the following:
        ...
        if (*end == 'l' || *end == 'L')
                return PyLong_FromString(s, (char **)0, 0);
        if (*end == 'r' || *end == 'R') {
		PyObject* cb=NULL;
		cb = PyDict_GetItemString(PyEval_GetBuiltins(),
					"_construct_rational");
		if (cb!=NULL) {
			*end = '\0';   /* remove trailing `r' */
			return PyObject_CallFunction(cb,"s",s);
			}
		}
        ...
(sure, more checks are needed for `cb').

My questions to Python experts are:

1) Would this work? What else I should be aware of?

2) How bad is the idea of modifing __builtins__ module as above? Is this
too unPythonic? Other ideas?

3) What are changes that these hooks will be accepted to Python core? ---
that is, after more careful coding and providing default rational number
class implemented in pure Python.

4) Is anybody else working with builtin rational number support for
Python?


Pearu






More information about the Python-list mailing list