Why isn't this a bug?

Russell Blau russblau at hotmail.com
Sun Jul 7 16:12:07 EDT 2002


ActivePython 2.2.1 Build 222 (ActiveState Corp.) based on
Python 2.2.1 (#34, Apr 15 2002, 09:51:39) [MSC 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> str(33L)
'33'
>>> str([33L])
'[33L]'
>>> c = 2/5.
>>> str(c)
'0.4'
>>> str((c,))
'(0.40000000000000002,)'

As the above example shows, the str() built-in function represents long and
float values one way if they are passed directly as the argument of the
function, but a different way if they are found inside a list or tuple (or
dict, although I didn't illustrate that above).

Digging into the source a bit, I found the reason for this.  Lists, tuples,
and dicts don't have built-in "__str__" methods, and if the str() function
can't find such a method then it defaults to using the __repr__ method.
Therefore, str() produces the same output as repr() when the argument is a
list, tuple, or dict (or any other object that doesn't have a __str__
method).  And the __repr__ methods for these objects, naturally enough,
recursively call __repr__ on each element of the sequence or mapping.

Ah hah, I thought, I've found a bug.  However, I did a search on
sourceforge.net and found that this issue (or at least part of it) had
already been submitted as a bug and rejected!  (It was number 506741, for
anyone who wants to look.)

If this is not a bug, however, it does raise a question about the design of
the language.  Granted, I suppose one *could* define the operation of the
built-in function str() so that exactly the same value can result in
different string representations depending on the context in which the value
is found (i.e., a long that is inside a list "looks" different than one that
is not inside a list); then, the output shown above is not a "bug" but is
the way the feature was designed to operate.  But why define your language
in such a way as to produce inconsistent output?  I don't see any value in
doing so, and it seems vaguely un-Pythonic (although I admit my
Pythonic-ness expertise is very limited).

Anyway, if anyone is interested in *changing* this "feature" in a future
version, I will point out that it can be done fairly easily by adding
methods called "list_str" "tuplestr" and "dict_str" to the files
listobject.c, tupleobject.c, and dictobject.c, respectively.  Each method
would be identical to the currently-defined methods "list_repr" "tuplerepr"
and "dict_repr" except that all calls to PyObject_Repr would be replaced by
calls to PyObject_Str.  In the case of lists and tuples, this would just
require changing one line:
    s = PyObject_Repr(v->ob_item[i]);
to
    s = PyObject_Str(v->ob_item[i]);
and adding the appropriate tp_str pointer in the PyTypeObject for each type.
(dictobject.c is a little different, since there are two calls to
PyObject_Repr() -- one for the key and another for the value, but the basic
idea is the same.)

Of course, if someone would like to explain why something so simple and
intuitive is a "bad idea," please enlighten me.  ;-)

--
I don't actually have a hotmail account but I do have one on excite.com if
you want to contact me.






More information about the Python-list mailing list