elii236
elii236

Reputation: 98

what's the different between "is True" and "== True" and when to use each?

the question is in the title. I have a dict of keys and each key value is True or False And I have a list of items. I want to iterate through the dict, and check if (key in list) == (or is) dict[key]

Which means I want to see if there is a match between the return value I will get from the "in" call and the value in the dict,

for example:

quick_dict = dict()
quick_list = list()
quick_dict['hi'] = True
quick_dict["hello"] = True
quick_dict["bye"] = False
quick_dict["bi"] = False
quick_dict['zi'] = True
quick_dict["zv"] = True


quick_list.append("hi")
quick_list.append("bye")
for key in quick_dict:
    if (key in quick_list) == quick_dict[key]:
        print(key)

Which one should I use in this case? and in general what's the different in this case?

Upvotes: 0

Views: 489

Answers (3)

James
James

Reputation: 36598

In Python the True and False (and None too) are called singleton objects. They exist in the process once and only once. Any assignment to these value will always be assigned to the same object. So this means any variable that are assigned to True ARE the same version of True (because there is only one version).

x = True
y = True
x is y
# True
(x is y) is True
# True

Generally, you don't use the either syntax in your question. If you want to check the if a value is True, you just pass it as is:

x = True
if x:
    print('hello world')

This is cleaner, simpler, and easier to read than:

x = True
if x == True:
    print('i am a computer')

Because you are adding an additional evaluation that does not need to take place. In the above example, Python evaluate x == True to True, then evaluates if True to continue the if block.

Except....

The one exception I have seen is sometime you want code to accept either a string or a boolean value, and make a decision based on what is passed. Matplotlib has a bit of this. In this case you might use x is True.

Here is an example of a version number loosener that accepts string or bools.

def format_version(version, how):
    allowed = ('full', 'major', 'minor', 'none', 'true', 'false', True, False)
    if how not in allowed
        raise ValueError(
            "Argument `how` only accepts the following values: {}".format(allowed)
        )

    n = version.count('.')
    if (n == 0) or (how=='full') or (how is True):
        return version
    if n == 1:
        major, minor = version.split('.')
        subs = ''
    if version.count('.') >= 2:
        major, minor, subs = version.split('.', 2)

    if how == 'major':
        return major + '.*'
    if how == 'minor':
        if not subs:
            return '{0}.{1}'.format(major, minor)
        return '{0}.{1}.*'.format(major, minor)

Here are specifically checking if True is passed because a simple boolean check on a string will be true as well. To be clear, this is not a good pattern, it just happens because you want your user to be able to pass a True/False value.

A better way of handling this is to convert to string, and then check the strings. Like this:

def format_version(version, how):
    how = str(how).lower()
    allowed = ('full', 'major', 'minor', 'none', 'true', 'false')
    if how not in allowed
        raise ValueError(
            "Argument `how` only accepts the following values: {}".format(allowed)
        )

    n = version.count('.')
    if (n == 0) or (how == 'full') or (how == 'true'):
        return version
    if n == 1:
        major, minor = version.split('.')
        subs = ''
    if version.count('.') >= 2:
        major, minor, subs = version.split('.', 2)

    if how == 'major':
        return major + '.*'
    if how == 'minor':
        if not subs:
            return '{0}.{1}'.format(major, minor)
        return '{0}.{1}.*'.format(major, minor)

Upvotes: 0

AirSquid
AirSquid

Reputation: 11883

In general, you don't want to test boolean variables with is or ==. Just say if ... or put it in a boolean expression by itself.

You want to test 2 conditions, it seems:

  1. Is the key in both collections
  2. Is the dict[key] True

So, you should just write

if key in quick_list and quick_dict[key]:
    # do something

If these lists or dictionaries are "large" you should just use set notation and take then iterate only over the intersection of the 2 sets, which automatically takes care of the first condition and shortens the loop to the intersection of the 2 collections like:

In [4]: quick_set = {1, 3, 5}                                                   

In [5]: quick_dict = {1: True, 2: True, 3: False, 4: True}                      

In [6]: matched_keys = quick_set.intersection(set(quick_dict.keys()))           

In [7]: for k in matched_keys: 
   ...:     if quick_dict[k] : print(k, quick_dict[k]) 
   ...:                                                                         
1 True

Upvotes: 1

Petar Luketina
Petar Luketina

Reputation: 449

Let's look at the code below:

x, y = True, True
u, v = [True], [True]

print(x is y)
print(u is v)

>>> True
>>> False

When using is, there is an added layer of complexity because you're dealing with how the variables are written into memory. We can see that True is stored in memory once. So x and y are hitting the same piece of memory when we call the variable.

Conversely, when we create lists, Python allocates two different places in the memory, one for each list. This means that after the sample code is run, we have True, [True], and [True] stored.

In your example, True and False are written in memory once, no matter how many times we assign them to a variable.

Variables:      x  y     u     v
                 \/      |     |
Memory:         True  [True] [True]

Upvotes: 0

Related Questions