Reputation: 98
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
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.
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
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:
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
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