It appears that if x is almost like short-hand for the longer if x is not None syntax. Are they functionally identical or are there cases where for a given value of x the two would evaluate differently?
I would assume the behavior should also be identical across Python implementations - but if there are subtle differences it would be great to know.
In the following cases:
test = False
test = ""
test = 0
test = 0.0
test = []
test = ()
test = {}
test = set()
the if test will differ:
if test: #False
if test is not None: #True
This is the case because is tests for identity, meaning
test is not None
is equivalent to
id(test) == id(None) #False
therefore
(test is not None) is (id(test) != id(None)) #True
The former tests trueness, whereas the latter tests for identity with None. Lots of values are false, such as False, 0, '', and None, but only None is None.
x = 0
if x: ... # False
if x is not None: ... # True
if x checks if x is considered as True.
In Python, everything has a boolean value (True/False).
Values that are considered as False:
False, None
0, 0.0, 0j
[], (), {}
''
Other instances that signal to Python that they are empty
Other values are considered as True. For example, [False], ('hello'), 'hello' are considered as True (because they are not empty).
When using if x is not None, you are checking if x is not None, but it can be False or other instances that are considered as False.
>>> x = None
>>> if not x:print x # bool(None) is False
None
>>> if x == None:print x
None
>>> x = False
>>> if not x:print x
False
>>> if x == None:print x
Finally, note that True and False are respectively equal to 1 and 0:
>>> True + 1
2
>>> False + 1
1
>>> range(1, 5)[False]
1
if x:
# Evaluates for any defined non-False value of x
if not x:
# Evaluates for any defined False value of x
if x is None:
# Evaluates for any instances of None
None is its own type, which happens to be False. "if not x" evaluates if x = None, only because None is False.
There aren't any subtle differences that I know of but there are exact methods to test for use for positivity/negativity in exact situations. Mixing them can work in some situations, but can lead to problems if they're not understood.
if x is True:
# Use for checking for literal instances of True
if x is False:
# Use for checking for literal instances of False
if x is None:
# Use for checking for literal instances of None
if x:
# Use for checking for non-negative values
if not x:
# Use for checking for negative values
# 0, "", None, False, [], (), {} are negative, all others are True
Related
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?
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:
Is the key in both collections
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
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]
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)
>>> if '' is not None:
... print'23333'
...
23333
I think (not None) is True and ('') is False so why it running print?
is and is not test for object identity, i.e., will test if '' and None are the same object, which they are not, so the test returns True in your case.
From the Python documentation:
The operators is and is not test for object identity: x is y is true
if and only if x and y are the same object. x is not y yields the
inverse truth value.
To put it another way, although '' and None have the same "truthiness", that is they both evaluate to False if you do bool(None) or bool(''), they to do not refer to the same object.
is not is a single operator, equal to the negation of is. Since '' is None is false, '' is not None is true.
But since is tests identity, not equality, '' is (not None) still won't do what you want.
I just stumbled across this and I couldn't find a sufficient answer:
x = ""
Why then is:
x == True
False
x == False
False
x != True
True
x != False
True
Am I supposed to conclude that x is neither True nor False?
to check if x is True of False:
bool("")
> False
bool("x")
> True
for details on the semantics of is and == see this question
Am I supposed to conclude that x is neither True nor False?
That's right. x is neither True nor False, it is "". The differences start with the type:
>>> print(type(""), type("x"), type(True), type(False))
builtins.str, builtins.str, builtins.bool, builtins.bool
Python is a highly object oriented language. Hence, strings are objects. The nice thing with python is that they can have a boolean representation for if x: print("yes"), e. g.. For strings this representation is len(x)!=0.
In a Boolean context, null / empty strings are false (Falsy). If you use
testString = ""
if not testString:
print("NULL String")
else:
print(testString)
As snakecharmerb said, if you pass the string to the bool() function it will return True or False based
>>> testString = ""
>>> bool(testString)
False
>>> testString = "Not an empty string"
>>> bool(testString)
True
See this doc on Truth Value Testing to learn more about this:
Python 2:
https://docs.python.org/2/library/stdtypes.html#truth-value-testing
Python 3:
https://docs.python.org/3/library/stdtypes.html#truth-value-testing
In python '==' tests for equality. The empty string is not equal to True, so the result of your comparison is False.
You can determine the 'truthiness' of the empty string by passing it to the bool function:
>>> x = ''
>>> bool(x)
False
In what order are the contents of the expression"word" in [] == False parsed? It seems to defy all logic:
>>> "word" in [] == False
False
>>> ("word" in []) == False
True
>>> "word" in ([] == False)
TypeError
How does Python actually interpret this expression, and why does it interpret it so?
Edit:
the most general case seems to be
>>> any_value in any_list == any_symbol_or_value
False
Normally you can find out operator precedence with this table..
But this is actually a tricky example:
Comparisons can be chained
arbitrarily, e.g., x < y <= z is
equivalent to x < y and y <= z, except
that y is evaluated only once (but in
both cases z is not evaluated at all
when x < y is found to be false).
See the notes on comparisons.
So "word" in [] == False is really
("word" in []) and ([] == False)
where the two [] are actually the same object.
This is useful for other comparisons, ie 0 < a < 10, but really confusing here!
word in [] is short-circuiting the first expression due to an implicit and. When it realizes that it's false, it stops evaluating the rest of the expression, which is a comparison between [] (the same entity that word was just testing against) and the value False. [] does not equal False, so the implicit "and" expression is false.
("word" in []) == False works as expected because ( ) makes the sub-clause finish and have its result compared to False.
Of course, once again, [] does not equal False.
To clarify the first case, you might test it like this:
foo = []
if ("word" in foo) and (foo == False):
print "True"
else:
print "False"
This is, functionally, what's going on.
I did several Boolean Comparisons:
>>> (True or False) is True
True
>>> (True or False) == True
True
It sounds like == and is are interchangeable for Boolean-values.
Sometimes it's more clear to use is
I want to know that:
Are True and False pre-allocated in python?
Is bool(var) always return the same True(or False) with the pre-allocated True(or False)?
Is it safe to replace == with is to compare Boolean-values?
It's not about Best-Practice.
I just want to know the Truth.
You probably shouldn't ever need to compare booleans. If you are doing something like:
if some_bool == True:
...
...just change it to:
if some_bool:
...
No is or == needed.
As commenters have pointed out, there are valid reasons to compare booleans. If both booleans are unknown and you want to know if one is equal to the other, you should use == or != rather than is or is not (the reason is explained below). Note that this is logically equivalent to xnor and xor respectively, which don't exist as logical operators in Python.
Internally, there should only ever be two boolean literal objects (see also the C API), and bool(x) is True should be True if bool(x) == True for any Python program. Two caveats:
This does not mean that x is True if x == True, however (eg. x = 1).
This is true for the usual implementation of Python (CPython) but might not be true in other implementations. Hence == is a more reliable comparison.
Watch out for what else you may be comparing.
>>> 1 == True
True
>>> 1 is True
False
True and False will have stable object ids for their lifetime in your python instance.
>>> id(True)
4296106928
>>> id(True)
4296106928
is compares the id of an object
EDIT: adding or
Since OP is using or in question it may be worth pointing this out.
or that evaluates True: returns the first 'True' object.
>>> 1 or True
1
>>> 'a' or True
'a'
>>> True or 1
True
or that evaluates False: returns the last 'False' object
>>> False or ''
''
>>> '' or False
False
and that evaluates to True: returns the last 'True' object
>>> True and 1
1
>>> 1 and True
True
and that evaluates to False: returns the first 'False' object
>>> '' and False
''
>>> False and ''
False
This is an important python idiom and it allows concise and compact code for dealing with boolean logic over regular python objects.
>>> bool([])
False
>>> bool([0])
True
>>> bool({})
False
>>> bool({False: False})
True
>>> bool(0)
False
>>> bool(-1)
True
>>> bool('False')
True
>>> bool('')
False
Basically 'empty' objects are False, 'non empty' are True.
Combining this with #detly's and the other answers should provide some insight into how to use if and bools in python.
Yes. There are guaranteed to be exactly two bools, True and False:
Class bool cannot be subclassed
further. Its only instances are False
and True.
That means if you know both operands are bool, == and is are equivalent. However, as detly notes, there's usually no reason to use either in this case.
It seems that all answers deal with True and False as defined after an interpreter startup. Before booleans became part of Python they were often defined as part of a program. Even now (Python 2.6.6) they are only names that can be pointed to different objects:
>>> True = 1
>>> (2 > 1)
True
>>> (2 > 1) == True
True
>>> (2 > 1) is True
False
If you have to deal with older software, be aware of that.
The == operator tests for equality The is keyword tests for object identity. Whether we are talking about the same object. Note, that more variables may refer to the same object.
== and is are both comparison operators, which would return a boolean value - True or False. True has a numeric value of 1 and False has a numeric value of 0.
The operator == compare the values of two objects and objects compared are most often are the same types (int vs int, float vs float), If you compare objects of different types, then they are unequal. The operator is tests for object identity, 'x is y' is true if both x and y have the same id. That is, they are same objects.
So, when you are comparing if you comparing the return values of same type, use == and if you are comparing if two objects are same (be it boolean or anything else), you can use is.
42 is 42 is True and is same as 42 == 42.
Another reason to compare values using == is that both None and False are “falsy” values. And sometimes it’s useful to use None to mark a value as “not defined” or “no value” while considering True and False values to work with:
def some_function(val = None):
"""This function does an awesome thing."""
if val is None:
# Values was not defined.
elif val == False:
# User passed boolean value.
elif val == True:
# User passed boolean value.
else:
# Quack quack.
Somewhat related question: Python != operation vs “is not”.