Why does Python log a SyntaxWarning for 'is' with literals?2020-01-21
Take this reasonable-looking code:
If we run it with Python 3.8+, we’ll see a warning message on line 2:
This is a new warning added in Python 3.8. From the release notes:
The compiler now produces a
SyntaxWarningwhen identity checks (
is not) are used with certain types of literals (e.g. strings, numbers). These can often work by accident in CPython, but are not guaranteed by the language spec. The warning advises users to use equality tests (
!=) instead. (Contributed by Serhiy Storchaka in bpo-34850.)
What does it mean that they “work by accident”? To understand that, let’s take a look at a broken example.
Take this new code:
It’s similar to the previous example.
We’re again assigning
x to an
int value, but this time construct it via the
Apart from this time, our message does not appear, only the warning:
If we follow the warning and change
==, the message will appear with no
Why didn’t it appear before?
It’s all to do with the difference between
== (the same for
is not and
is checks for identity - if the two variables point to the exact same object.
== checks for equality - if the two variables point at values are equal.
That is, if they will act the same way in the same situations.
Identity implies equality, but not the other way round.
CPython (the main implementation of Python) can reuse some objects to improve performance.
For example, when it starts up, it pre-creates
int objects for the numbers -5 to 256.
Other Python implementations such as MicroPython don’t necessarily do that.
In our first example, when we assigned
x to 200 on line 1, and compared it to another definition of
200 on line 2, CPython would reuse the same
int object for both.
is operator on line 2 returned
In our second example, the
1000 on line 2 was created at import time, when Python parsed the code.
1000 value in
x on line 1 was only constructed at runtime.
Since it’s outside the range of pre-created
int objects, that would be a newly created
is operator returned
SyntaxWarning check applies to other types with literals too - for example
Identity versus equality is a core programming concept that’s worth nailing. Here’s some other reading with explanations that might beat mine!
“Objects and Values” in the free book “How to Think Like a Computer Scientist: Learning with Python.”
Trey Hunner has a great article on sentinel values that covers Equality vs identity.
Stack Overflow on What’s with the integer cache maintained by the interpreter?
Flake8 has a similar check with its error code F632. If you’re looking to improve the general quality of your Python code, running Flake8 as part of your development cycle will help.
Hope this helps you understand and fix this warning,
Working on a Django project? Check out my book Speed Up Your Django Tests which covers loads of best practices so you can write faster, more accurate tests.
One summary email a week, no spam, I pinky promise.
- Why does Python log a SyntaxWarning saying "object is not callable"?
- Why does Python log a SyntaxWarning saying "object is not subscriptable"?
- Why does Python log a SyntaxWarning saying "assertion is always true"?
- Why does Python log a SyntaxWarning saying "list indices must be integers or slices"?
© 2020 All rights reserved.