Shubham saini
Shubham saini

Reputation: 9

variable is not None works but not variable doesn't work

I was trying to solve a dynamic programming problem in Pyhon 3.x. I wanted to create a memo dictionary object. After assigning default value of None to memo parameter, the check for None with not object doesn't seem to work, but if I change it to object is None, it works fine. By doesn't work, I mean this condition doesn't evaluate to True in case of not object, and the following indented code isn't executed. This results in TLE on LeetCode. But using is None check does work, and it assigns a dictionary to memo, and thus caching works as intended, and the solution passes.

Why does this happen?

        def lcs(i, j, memo = None):
            if not memo:
                memo = {}

vs

        def lcs(i, j, memo = None):
            if memo is None:
                memo = {}

I called the function with return lcs(0, 0).

Edit: On my system Python IDLE, both expressions evaluate to True. So I think, the LeetCode platform handles the code differently.

Code on my system.

Edit 2: sometime after @buran pointed out, these partial snippets were producing the expected result on LeetCode too, I also tried the partial snippets, and indeed they were giving the expected result. But then when I tried the whole code(used from past submission), surprisingly it also gave the expected result (new memo was actually created). I wasn't able to actually reproduce the problem I faced earlier until today. for a different problem, the code is again showing the same behavior, Now I think I am missing something here. That's why I'm posting the whole code this time. Can someone spot and explain why both these codes give different result.

class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        
        def lps(l, r, memo = None):
            if memo is None:
                memo = {}
            if (l, r) not in memo:
                if l > r:
                    memo[(l, r)] = 0
                elif l == r:
                    memo[(l, r)] = 1
                elif s[l] == s[r]:
                    memo[(l, r)] = lps(l+1, r-1, memo) + 2
                else:
                    memo[(l, r)] = max(lps(l+1, r, memo), lps(l, r-1, memo))
            return memo[(l, r)]
        
        return lps(0, len(s)-1)

vs

class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        
        def lps(l, r, memo = None):
            if not memo:
                memo = {}
            if (l, r) not in memo:
                if l > r:
                    memo[(l, r)] = 0
                elif l == r:
                    memo[(l, r)] = 1
                elif s[l] == s[r]:
                    memo[(l, r)] = lps(l+1, r-1, memo) + 2
                else:
                    memo[(l, r)] = max(lps(l+1, r, memo), lps(l, r-1, memo))
            return memo[(l, r)]
        
        return lps(0, len(s)-1)

Can someone please also tell if and what should I remove from my past edits or the original post. This is becoming a really long post. (I'm new here)

Upvotes: 0

Views: 846

Answers (3)

tdelaney
tdelaney

Reputation: 77377

From Truth Value Testing

By default, an object is considered true unless its class defines either a bool() method that returns False or a len() method that returns zero.

An empty dict has length zero, so is False. If you call lcs with a memo dictionary, but that dictionary doesn't happen to have anything in it, it will test False and if not memo: memo = {} will create a new memo object for you. That code can't tell the difference between an empty memo and None.

The if memo is None is the proper way to assign a memo only if the caller hasn't passed one in.

Upvotes: 1

CosmicPredator
CosmicPredator

Reputation: 109

not is a keyword which is equivalent to !=. So it has totally different meaning.

You can use not keyword as below (for example)

def lcs(i, j, memo = None):
            if memo is not None:
                memo = {}

The above code is equivalent to

def lcs(i, j, memo = None):
            if memo != None:
                memo = {}

If you want to use not keyword that badly, then use this code.

def lcs(i, j, memo = None):
            if not memo == None:
                memo = {}

If you find have any doubts, let me know.

Upvotes: 1

Rhett Harrison
Rhett Harrison

Reputation: 432

It's been awhile since I've used Python so bear with me but I think I can explain the general programming concept.

In the first one you are checking if memo doesn't exist.

if not memo

Meaning to continue if memo does not exist.

In the second one you are checking that memo does exist and that it is set to None.

if memo is None

To continue if memo exists (a pre-condition to going into the check) and it is set to None

Upvotes: 0

Related Questions