I miss a function able to convert the string representation of a Python primitive number (int, long, float, complex) to an actual number, basically the reverse of repr for numbers. The only option I know of that doesn't involve inspecting the individual digits is eval, which doesn't cut it -- besides the obvious security implications, it tends to be slow when used en masse. What I have in mind is something along the lines of:
read_number('1') 1 read_number('1.') 1.0 read_number('3.14') 3.1400000000000001 read_number('1000000000000000000') 1000000000000000000L read_number('2+3j') (2+3j) read_number('1e100') 1e+100 read_number('bla') Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: invalid numeric value 'bla'
A sample implementation, a variation of which I use in an in-house project, follows. It does inspect the string to determine its type, but does so in a simple C loop which is quite fast for numeric input. It leaves the actual conversion to the Python's API code that knows what it's doing. Because of that it's simple and fast, but still (to my knowledge) correct.
PyObject * read_number(PyObject *str) { int isfloat = 0, iscomplex = 0;
/* First, intuit the type based on characters that appear in the string. */ const char *s = PyString_AS_STRING(str); const char *end = s + PyString_GET_SIZE(str); const char *q; for (q = s; q < end; q++) { char c = *q; if (c == '.' || c == 'e') isfloat = 1; else if (c == 'j') iscomplex = 1; else if (c != '-' && c != '+' && !isdigit(c) && !isspace(c)) { PyErr_Format(PyExc_ValueError, "invalid numeric value '%s'", s); return NULL; } }
/* Now that the type is known, construct the number, leaving the actual error checking to the constructors. */ if (iscomplex) return PyObject_CallFunctionObjArgs((PyObject *) &PyComplex_Type, str); else if (isfloat) return PyFloat_FromString(str, NULL); else /* handles ints and longs */ return PyInt_FromString((char *) s, NULL, 10); }
Would anyone else find this kind of function useful?