The error we’re handling today is a real-life example simplified to the following Python code:
# user inputs several numbers in form of strings (1, 2, 3 and 123)
# which are then used to construct 2 strings
s1 = "".join(["1", "2", "3"])
s2 = "123"
# if the numbers in the constructed strings are different,
# the program flow should stop
if s1 is not s2:
raise RuntimeError("s1 is not s2!")
# program flow continues...The variables s1 and s2 both end up being 123, but when we run this code, we see:
Traceback (most recent call last):
File "/home/main.py", line 9, in <module>
raise RuntimeError("s1 is not s2!")
RuntimeError: s1 is not s2!What’s even worse, in the other parts of the app, where s1 and s2 are constructed differently, there are the same comparisons:
s1 = "123"
s2 = "123"
if s1 is not s2:
raise RuntimeError("s1 is not s2!")
# program flow continues...But this time the exception is not thrown, so the same comparison seems to give different results for the same s1 and s2 strings.
What does it mean?
The issue comes from misunderstanding the difference between identity and equality in Python. The is operator does not check whether two variables contain the same value. It checks whether both variables point to the exact same object in memory.
- == asks: “Do these objects have the same content?”
- is asks: “Are these literally the same object?”
For example:
s1 = "123"
s2 = "123"
print(s1 == s2) # True
print(s1 is s2) # maybe True, maybe FalseThe first comparison checks the values of the strings, so it reliably returns True. The second comparison depends on Python’s internal memory optimizations. Sometimes Python “interns” strings, meaning it reuses the same object for performance reasons. In those cases, s1 is s2 may accidentally return True, but not always.
In this version:
s1 = "".join(["1", "2", "3"])
s2 = "123"
print(s1 == s2) # True
print(s1 is s2) # FalseBoth strings contain exactly the same text, but they were created differently, so Python stores them as separate objects. This makes is unreliable for value comparison.
How to fix it?
Use == whenever you want to compare values. Correct version:
s1 = "".join(["1", "2", "3"])
s2 = "123"
if s1 != s2:
raise RuntimeError("s1 is not s2!")Reserve is for cases where you truly want to check object identity. The most common use is comparing with None:
if value is None:
print("No value provided")Read also:
- Bug of the week #12
- Sharing variable between bash scripts
- A 40-line LLM-based bash command executor in Python
- GTest and short-circuit evaluation in C++
- AI is powerful. Snippets are instant.
- From AUTOSAR to S-Core: the first C++ pub/sub implementation
- How to write Arduino Uno code with Python?
- Combining Bazel with Docker
- Running commands with timeout on Linux
- Running Python unit tests with CMake
- Thirdparty dependencies with FetchContent
- Bug of the week #11
- Combining CMake with Docker
- How to search the internet from Linux terminal?
- Folding expressions in C++
- How to derive from an enum in Python?
- Bug of the week #10
- Trying ROS2: client/server within a single container
- Make C++ a better place #4: Go as an alternative
- How to convert hex to dec in Linux terminal?
- Setting up a Python project with CMake
- Separating builds for different configs with Bazel
- Trying ROS2: pub/sub within a single container
- Bug of the week #9
- UDP multicasting with Python
- Destruction order vs thread safety in C++
- Let’s review some code: C++ #2
- Make C++ a better place #3: D as an alternative
- Registering callback using std::function in C++
- Bug of the week #8
- TCP client/server with Python
- Simple menus in Bash scripts with select
- Calling member function on a nullptr in C++
- Bug of the week #7
- Python lru_cache explained
- How to dockerize a Python application?
- Make C++ a better place #2: CppFront as an alternative
- Parameters combinations in GoogleTest
- Data transfer with curl
- Python reduce explained
- Bug of the week #6
- Custom literals in C++
- Linux and hash command
- 5 Python good practices which make life easier
- Let’s review some code: Python #1
- Make C++ a better place #1: What does better mean
- Enums vs enum class in C++
- Bug of the week #5
- UDP client/server with Python
- Hard links in Linux
- Functions calling order in unit tests in C++
- Bug of the week #4
- Yield in Python – state machines, coroutines and more
- Copy files from another branch with Git
- Make C++ a better place #0: Introduction
- 5 misconceptions about std::move in C++
- How to use xargs on Linux?
- How to test method call order with unittest in Python?
- Bug of the week #3
- Build & run C++ unit tests with CMake









