-
-
Notifications
You must be signed in to change notification settings - Fork 30k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Confusing error message when None used in expressions, eg. "'NoneType' object has no attribute 'foo'" #72888
Comments
Python's error message when you let None accidentally sneak into an expression where it doesn't belong could be better. The canonical example is attribute lookup: >>> a = None
>>> a.foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'foo' This assumes that the programmer knows there is only one object of type NoneType, and it is None. That's a lot to assume of a beginner, whether they are coming from another programming language ("null has a type? that's crazy talk!") or are completely new to programming ("null? none? nil? wat...??"). There are plenty of other places this use of NoneType in error messages comes up: >>> a + 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
>>> 1 + a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
>>> len(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'NoneType' has no len()
>>> a < 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'NoneType' and 'int' I think we can do better than this. For example, here is an proposed improvement to user experience for getting and setting attributes on None: >>> a.foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: attempt to access attribute 'foo' of None, but None has no attributes
>>> a.foo = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: attempt to set attribute 'foo' on None, but None is read-only Let the bikeshedding commence. I have a working patch, but need to write tests. Will upload it here when that is done. |
Based on a brief conversation with Brett Cannon at PyCon Canada the other day. Thanks for the idea, Brett! |
That presumably means adding special None support to all the places None can appear in a message, where now the code treats None like it does every other object. I'm not sure the added complexity is worth it, especially since NoneType would still creep in anywhere we'd forgotten to "fix". I'm not voting -1, but I'm dubious. Maybe we should just make NoneType's name be 'None' :) |
Approximate counts. C code: Python code: Is it worth changing about 800 places in CPython code? Not counting third-party code. |
I have doubts also. The issue is the same for NotImplemented, though the occurrence is much rarer, and similar for Ellipsis. >>> NotImplemented.foo
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
NotImplemented.foo
AttributeError: 'NotImplementedType' object has no attribute 'foo'
>>> Ellipsis.foo
Traceback (most recent call last):
File "<pyshell#20>", line 1, in <module>
Ellipsis.foo
AttributeError: 'ellipsis' object has no attribute 'foo' Replacing the type name with the object name works for this message, but not for the type errors. Replacing 'NoneType' with 'None' in error messages will break code that does something like "if 'NoneType' in err.args[0]" in an exception message. The same replacement would have to be make in user code. Fortunately, it would continue to work with older versions. |
Definitely not. My aim is not to fix every possible reference to "instance of 'NoneType'", just the handful of cases that are most frequently encountered, especially if we think they are likely to be confusing to beginners. That's why I've only modified getting and setting attributes so far; I wanted to see what the cost/benefit is like. Renaming 'NoneType' to 'None' sounds like a much easier approach, if it works. But then saying "instance of" + tp_name comes out weird. "Instance of NoneType" is confusing if technically accurate; "instance of None" is both confusing and technically inaccurate. Hmmmm. Still mulling. |
I think changing only some of the NoneTypes to None will be confusing. I think we should close this. It's a nice thought, but not worth the trouble. |
All 4 core developers were at least dubious. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: