Description
Feature or enhancement
Proposal:
Problem description
In more recent versions of Python, for uncaught NameError
s and AttributeErrors
, the system tries to suggest names that might have been typoed:
>>> intt
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'intt' is not defined. Did you mean: 'int'?
However, the suggestion logic apparently does not take underscore conventions into account:
>>> _foo = 1
>>> foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined. Did you mean: '_foo'?
Commonly, leading underscores on names are used by convention to mark names that should not be referenced directly in client code. (Of course, it's occasionally necessary or desirable to call dunder methods directly, particularly when inheritance is involved, but generally not outside of classes.)
This has the negative effect, that Python itself could recommend that users invoke undocumented, unstable or unintentional APIs without good reason. One current real-world example of this occurs with Pandas, where version 2.0 removed the append
method from DataFrame
s, but there happens to be an _append
method left behind as an implementation detail:
>>> import pandas as pd
>>> pd.DataFrame().append
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/path/to/lib/python3.11/site-packages/pandas/core/generic.py", line 6296, in __getattr__
return object.__getattribute__(self, name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'DataFrame' object has no attribute 'append'. Did you mean: '_append'?
Proposal
I propose that: when the invalid identifier or attribute name does not already start with an underscore, valid names that do start with an underscore should be excluded from suggestions. As mentioned in the linked discussion, there is already precedent for this -
- As implemented by
help
:
>>> import pydoc
>>> pydoc.pager = print # to simplify behaviour for the example
>>> class Example:
... __slots__ = [] # to simplify behaviour for the example
... def method(self): pass
... def _method(self): pass
...
>>> help(Example)
Help on class Example in module __main__:
class Example(builtins.object)
| Methods defined here:
|
| method(self)
>>>
- When using star-imports:
>>> _, name, result = 1, 2, {}
>>> exec('from __main__ import *', result)
>>> '_' in result
False
>>> 'name' in result
True
It still makes sense IMO to suggest underscore names when the invalid name already starts with an underscore - even mixing and matching single- and double-underscore cases. For example, _init_
is a very plausible typo for __init__
, especially for beginners who are learning from a book or an old PDF.
Has this already been discussed elsewhere?
I have already discussed this feature proposal on Discourse