Python mind-teaser: Make the function return True
Hi everyone! 👋 I was browsing /r/python and came across this post:
The challenge was easy. Provide such an input that if 1 is added to it, it is the instance of the same object but if 2 is added it is not.
Solution 1: Custom class
The way I personally thought to solve this challenge was this:
def check(x):
if x+1 is 1+x:
return False
if x+2 is not 2+x:
return False
return True
class Test(int):
def __add__(self, v):
if v == 1:
return 0
else:
return v
print(check(Test()))
# output: True
Let me explain how this works. In Python when we use the +
operator Python calls a different dunder method depending on which side of the operator our object is. If our object is on the left side of the operator then __add__
will be called, if it is on the right side then __radd__
will be called.
Our Test object will return 0
if Test() + 1
is called and 1
if 1 + Test()
is called. The trick is that we are overloading only one dunder method and keeping the other one same. This will help us pass the first if condition. If you take a second look at it you will see that it helps us pass the second if check as well because we simply return the input if it is not 1 so Test() + 2
will always be similar to 2 + Test()
.
However, after reading the comments, I found another solution which did not require a custom class.
Solution 2: A unique integer
User /u/SethGecko11 came up with this absurdly short answer:
def check(x):
if x+1 is 1+x:
return False
if x+2 is not 2+x:
return False
return True
print(check(-7))
# output: True
Only -7 works. Any other number will not return True. If you are confused as to why this works then you aren’t alone. I had to read the comments to figure out the reasoning.
So apparently, in Python, integers from -5 to 256 are pre-allocated. When you do any operation and the result falls within that range, you get the pre-allocated object. These are singletons so the is
operator returns True
. However, if you try using integers which don’t fall in this range, you get a new instance.
The memory requirement for pre-allocating these integers is not that high but apparently the performance gains are huge.
So when you use -7 as input, you get a new instance of -6 but the same instance when the answer is -5. This doesn’t work with the upper bound (256) precisely because of the way if statements are constructed. 255 would work as an answer if the check function was implemented like this:
def check(x):
if x+1 is not 1+x:
return False
if x+2 is 2+x:
return False
return True
I hope you learned something new in this article. I don’t think you would ever have to use this in any code-base ever but it is a really good mind-teaser which can catch even seasoned Python developers off-guard.
Happy programming! I will see you in the next article 😊
Andrzej Klajnert (@aklajnert)
Yasoob
In reply to Andrzej Klajnert (@aklajnert)
Antonio Frontino
Yasoob
In reply to Antonio Frontino
Justin T Washington