Can we make 1 == 2 true?

PythonCpythonPython Internals

Python Problem Overview


Python ints are objects that encapsulate the actual number value. Can we mess with that value, for example setting the value of the object 1 to 2? So that 1 == 2 becomes True?

Python Solutions


Solution 1 - Python

Yes, we can. But don't do this at home. Seriously, the 1 object is used in many places and I have no clue what this might break and what that might do to your computer. I reject all responsibility. But I found it interesting to learn about these things.

The id function gives us the memory address and the ctypes module lets us mess with memory:

import ctypes

ctypes.memmove(id(1) + 24, id(2) + 24, 4)

print(1 == 2)

x = 40
print(x + 1)

Output:

True
42

[Try it online!][3]. I tried it there because such sites have got to be protected from our hacking anyway.


More explanation / analysis:

The memmove copied the value from the 2 object into the 1 object. Their size is 28 bytes each, but I skipped the first 24 bytes, because that's the object's reference count, type address, and value size, as we can view/verify as well:

import ctypes, struct, sys

x = 1
data = ctypes.string_at(id(x), 28)
ref_count, type_address, number_of_digits, lowest_digit = \
    struct.unpack('qqqi', data)

print('reference count: ', ref_count, sys.getrefcount(x))
print('type address:    ', type_address, id(type(x)))
print('number of digits:', number_of_digits, -(-x.bit_length() // 30))
print('lowest digit:    ', lowest_digit, x % 2**30)

Output ([Try it online!][4]):

reference count:  135 138
type address:     140259718753696 140259718753696
number of digits: 1 1
lowest digit:     1 1

The reference count gets increased by the getrefcount call, but I don't know why by 3. Anyway, ~134 things other than us reference the 1 object, and we're potentially messing all of them up, so... really don't try this at home.

The "digits" refer to how CPython stores ints as [digits in base 230][5]. For example, x = 2 ** 3000 has 101 such digits. Output for x = 123 ** 456 for a better test:

reference count:  1 2
type address:     140078560107936 140078560107936
number of digits: 106 106
lowest digit:     970169057 970169057

[3]: https://tio.run/##NYoxDoAgEAT7e8WVEI0RpLDhNUoixcEFicHXnyRqNTOb5bseOS0rF5FInEvFrd4cToCXEwWifAUVd2U0DmjdiN3t704DcImpKoPeo@3Z0KObv7X1n9EiDw "Python 3.8 (pre-release) – Try It Online" [4]: https://tio.run/##bZDBbsMgEETvfMVeKuPIcdrkElnKn1RCBLCDmgCGtWp/vbuEpo2q@oIZ7cybJSx48e5wDHFd7S34iKBwCSY1kDBOCulcEmMznOCNaYmSfspESwPWDUIit5rPdQP7Y82i6YXykyNjnhJS62gSxbnpdjZR@F5oO1gk5eo/TcJypdR3BvQVaju5INUHr8ZxtFUDGVwzFgiIvCKGicYpA3dSBzTxxKXC7WCQlLtA1eqHM1eC70pdxlV/a9IqWcimH1epDr6HUr2r/ltny7dze7YorsYNeOE17HZweP2NKfuWjAf8@Q0amOEF9psNmdb1Cw "Python 3.8 (pre-release) – Try It Online" [5]: https://github.com/python/cpython/blob/247480a21cb165efdacc346a2d589dfc27e18283/Include/cpython/longintrepr.h#L11-L39

Solution 2 - Python

In Python 2, there's a much simpler approach - True and False aren't protected, so you could assign things to them.

>>> True = False
>>> (1 == 2) is True
True

Solution 3 - Python

If you'd prefer not to mess with the actual contents of cached int or bool objects, you can fake making 1 == 2 like so:

>>> import builtins
>>> import sys
>>>
>>> def displayhook(value):
...     if value is False:
...         value = True
...     elif value is 1:
...         value = 2
...     text = repr(value)
...     sys.stdout.write(text)
...     sys.stdout.write('\n')
...     builtins._ = value
...
<stdin>:4: SyntaxWarning: "is" with a literal. Did you mean "=="?
>>> sys.displayhook = displayhook
>>> 1
2
>>> 1 == 2
True

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKelly BundyView Question on Stackoverflow
Solution 1 - PythonKelly BundyView Answer on Stackoverflow
Solution 2 - PythonHollowayView Answer on Stackoverflow
Solution 3 - Pythondan04View Answer on Stackoverflow