[Python-ideas] Better error messages [was: (no subject)]

Stephen J. Turnbull turnbull.stephen.fw at u.tsukuba.ac.jp
Tue Nov 29 21:14:56 EST 2016


Mariatta Wijaya writes:

 > > NameError: name 'length' is not defined
 > 
 > > A better message might be:
 > 
 > > Python doesn't recognise the function "length". Did you mean
 > > len?'

This particular change would be useful to a beginning Python
programmer.  I've made that error often enough myself (maybe I'm not a
good example, though, in Lisp the generic function with the same role
*is* called "length", so I make that error even today).

But I wonder if it's a good example for the generic case.  An error
message of the form 'Python doesn't recognize the function "<name>".
Did you mean "<name>"?' could easily be misleading.  Python has
functions, but they're a type of object.  "length" is a name, which is
not an object.  The expected type of the object is not function, it's
callable.  So consider:

    class Blog:
        pass

    blog = log()

    NameError: Python doesn't recognize the function "log".  Did you
    mean "Blog"?

I suspect that might cause cognitive dissonance in a beginner who
thinks of a class as a type or data structure and not as a function.
And "doesn't recognize the callable" might be awkward (or beginners
might get used to it very quickly, I don't know).

Also, how do you propose deciding on the alternative to suggest?  In
this particular case, I expect most developers would agree
intuitively.  But the Hamming distance is pretty large: 3 of a length
of 6.  Would you have a dictionary of common errors, and then scan the
namespace for minimum Hamming distance among defined names with the
right type of value?

How about:

    class Blog:
        pass

    blog = get_blog_for_date(someday)

    logn = log(blog.size)

    NameError: Python doesn't recognize the function "log".  Did you
    mean "Blog"?

Wouldn't

    NameError: Python doesn't recognize the name "log".  Perhaps
    you need to import the "math" module?

be a better message here?  On second thought, that might imply that
calling with the unqualified name is generally the best style, and
teach the beginner to insert

    from math import *

at the top of the module, thus fixing all such errors.  We probably
don't want that, so maybe

    NameError: Python doesn't recognize the name "log".  There are
    functions named "log" in the "math" module and the "cmath" module.

would be better yet.

I definitely agree that there are times when Python's error messages
are quite impenetrable for the beginner, and improvement is
desirable.  I think that I would probably attack this by looking at
the builtin namespace and a few stdlib namespaces (math, string, and
maybe cmath come immediately to mind), and create a dictionary of
"intuitive beginner errors".  Then trap NameErrors, and preferentially
emit the message from the dictionary on exact matches.  Actually, come
to think of it, two dictionaries, one for the builtin namespace, one
for the selected stdlib, and the following heuristic:

    if name in common_builtin_typos:
        emit(common_builtin_typos[name])
    else:
        errors = small_hamming_distance(name, current_namespace, syntax(name))
        if errors:
            emit(errors)
        else:
            errors = exact_matches_in_imported_modules(name)
            if errors:
                emit(errors)
            elif name in common_unimported_stdlib_names:
                emit(common_unimported_stdlib_names[name])
            else:
                emit(error_you_would_have_emitted_anyway)

In other words, I don't see a good systematic way to go about this,
just pile up heuristics (and maybe remove some as they prove
unuseful!)

Steve




More information about the Python-ideas mailing list