我们能使1 = = 2为真吗?

Pythonint是封装实际数值的 物品。我们是否可以改变这个值,例如将对象 1的值设置为2?所以 1 == 2变成了 True

7773 次浏览

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!. 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!):

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. 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

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

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