Is it safe to replace '==' with 'is' to compare Boolean-values - python

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”.

Related

Difference between if not: and if False:

I have a probably quite simple question but was wondering between the difference of these two statements:
if not os.path.isfile(file):
#Do some stuff
if os.path.isfile(file) is False:
#Do some stuff
What are the differences (if any) between the two? To my understanding they both return a True or False value, so is it just a matter of preference or are there any significant differences?
In python (and other dynamic languages) there is the concept of truthy/falsy value. True/False are not the only things that evaluate as true/false
if not []:
print("this will be printed")
if [] is False:
print("this won't")
Another problem is that you should compare with x == False, and not x is False. The False is a singleton object in the current implementation of CPython, but this is not guaranteed by the specification.
In your case, since we know os.path.isfile returns True or False, there is no difference.
In general, there are a lot of objects in python which, when interpreted as boolean, will evaluate to False.
Think of this:
empty_list = []
if not empty_list:
print('List is not empty')
if empty_list is False:
print('List is False')
Among the others, None, "" and [] will evaluate to False.
So testing with not variable is usually the preferred way.
It's usually better to use the first, since it works even if you're not checking an actual boolean value in a Python implementation where False is a singleton object.
Uniformity is good, and so is portability.
>>> if 0 is False: print "false"
>>> if not 0: print "false"
false
>>> if [] is False: print "false"
>>> if not []: print "false"
false
>>> if "" is False: print "false"
>>> if not "": print "false"
false
It also protects against mishaps like this:
>>> False = 1
>>> True == False
True
You should know: False == 0 == None in case of if condition. If you use if not, you can cover all version of False (zero value). If you use == False you cannot handle the 0 or None. if not is recommended. The is operator is a different story (is not same as ==) but you can read more details on this link: Understanding Python's "is" operator

Empty String Boolean Logic

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

Precise Membership Test in Python

The in operator tests for equivalence using comparison, but Python's comparison isn't precise in the sense that True == 1 and 0 == False, yielding -
>>> True in [ 1 ]
True
>>> False in [ 0 ]
True
>>> 1 in [ True ]
True
>>> 0 in [ False ]
True
whereas I need a precise comparison (similar to === in other languages) that would yield False in all of the above examples. I could of course iterate over the list:
res = False
for member in mylist:
if subject == member and type( subject ) == type( member ):
res = True
break
This is obviously much less efficient then using the builtin in operator, even if I pack it as a list comprehension. Is there some native alternative to in such as a list method or some way to tweak in's behavior to get the required result?
The in operator is used in my case for testing the uniqueness of all list members, so a native uniqueness test would do as well.
Important note: The list may contain mutable values, so using set isn't an option.
Python version is 3.4, would be great for the solution to work on 2.7 too.
EDIT TO ALL THOSE WHO SUGGEST USING IS:
I look for a non-iterating, native alternative to a in b.
The is operator is not relevant for this case. For example, in the following situation in works just fine but is won't:
>>> [1,2] in [[1,2]]
True
Please, do read the question before answering it...
in doesn't test for equivalence at all. It checks if an item is in a container. Example:
>>> 5 in [1,2,3,4,5]
True
>>> 6 in [1,2,3,4,5]
False
>>> True in {True, False}
True
>>> "k" in ("b","c")
True
What you are looking for is is.
>>> True == 1
True
>>> True is 1
False
>>> False == 0
True
>>> False is 0
False
EDIT
After reading your edit, I don't think there is something built in in python libraries that suits your needs. What you want is basically to differentiate between int and bool (True, False). But python itself treats True and False as integers. This is because bool is a subclass of int. Which is why True == 1 and False==0 evaluates to true. You can even do:
>>> isinstance ( True, int)
True
I cannot think of anything better than your own solution, However, if your list is certain to contain any item not more than once you can use list.index()
try:
index_val = mylist.index(subject)
except ValueError:
index_val = None
if (index_val!=None):
return type(subject) == type(member)
Since index is built-in, it might be a little faster, though rather inelegant.
Python in operator is precise and the behavior you're complaining of is perfectly expected, since bool is a subclass of int.
Below is the excerpt of the official Python documentation describing the boolean type:
Booleans
These represent the truth values False and True. The two objects representing the values False and True are the only Boolean objects. The Boolean type is a subtype of plain integers, and Boolean values behave like the values 0 and 1, respectively, in almost all contexts, the exception being that when converted to a string, the strings "False" or "True" are returned, respectively.
You can also have a look at PEP 285.
You're looking for the is operator:
if any(x is True for x in l):
...
is, however, isn't exactly === from other languages. is checks identity, not just equality without type coercion. Since CPython uses string and integer interning, two objects that are equal may not be the same object:
In [19]: a = '12'
In [20]: b = '123'
In [21]: a += '3'
In [22]: a is b
Out[22]: False
In [23]: a == b
Out[23]: True
In [27]: 100001 is 100000 + 1
Out[27]: False
In [28]: 100001 == 100000 + 1
Out[28]: True
In Python 3, None, True, and False are essentially singletons, so using is for discerning True from 1 will work perfectly fine. In Python 2, however, this is possible:
In [29]: True = 1
In [31]: True is 1
Out[31]: True
Equality can be overridden __eq__ method, so you can define an object that is equal to any other object:
In [1]: %paste
class Test(object):
def __eq__(self, other):
return True
## -- End pasted text --
In [2]: x = Test()
In [3]: x == None
Out[3]: True
In [4]: x == True
Out[4]: True
In [5]: x == False
Out[5]: True
In this case, how would === work? There is no general solution, so Python has no built-in method of lists that does what you want.

"A is not B" vs "A is (not B)"

I'm a little bit scared about the "is not" operator and the possibility that "is not X" is interpreted when "is (not X)" was intended. Do exist some expressions A and B such that:
A is not B
is different from
A is (not B)
?
addendum.
Is it considered good practice to use this operator? Should't not (A is B) be preferred?
They're definitely different. The latter case evaluates not X in a boolean context first and then checks to see if the two objects are the same object (either True or False).
Consider:
False is not []
This expression is trivially True since False and [] are quite clearly different objects. 1
vs.
False is (not [])
This expression is False since not [] evalutes to True and False and True are different objects.
Of course, this is just one example. It gets even easier to find examples if you don't use False and True explicitly as the second expression will always be False and the first expression will (almost) always be True...
3 is not 0 # True
3 is (not 0) # False
1Note that is not is a single operator in the same vein as not in.
Yes:
A = 0
B = 1
Try it and you'll be really scared:
>>> A = 0
>>> B = 1
>>> A is not B
True
>>> A is (not B)
False

Boolean testing a list in Python

I was testing a list to see if it's empty or not. Normally I use len(list) == 0 and I vaguely remembered reading a little while ago that the correct way to test if a list is empty was whether it was True or false.
So I tried list is False, and that returned False. Maybe I'm suppose to be using == ?
Nope, that also returned false. list is True, returned false as did list == True.
Now I'm confused so I do a quick google and end up at: Best way to check if a list is empty
The top answer is:
if not a:
print "List is empty"
So I search around some more and end up in the python manual where 4.1 states:
Any object can be tested for truth value, for use in an if or while condition or as operand of the Boolean operations below. The following values are considered false:
any empty sequence, for example, '', (), [].
Now I'm plain confused. If I test a list as if not list, it works fine. But if an empty list is false, then why can't I just do if list is False or if list == False?
Thanks
An empty list is not False, but when you convert it to a boolean, it converts to False. Likewise for dicts, tuples, strings, etc.:
>>> [] == False
False
>>> bool([]) == False
True
>>> {} == False
False
>>> bool({}) == False
True
When you put something in the condition of an if clause, it is its boolean value that is used for testing the if. That's why if someList is the same as if bool(someList). Likewise, not foo does a boolean not, so not [] equals True.
As other have said, in python bool([]) == False. One thing that is frequently exploited by python programmers is that the operators and and or don't (necessarily) return True/False. Consider the following:
3 and 4 #returns 4
0 and 8 #returns 0 -- This is short-circuit evaluation
0 or 8 #returns 8
True or 0 #returns True -- This is short-circuit evaluation
[] or False #returns False
False or [] #returns []
What happens in an if statement is that the condition gets evaluated as above and then python implicitly calls bool on the result -- So you can think of it as:
if condition:
is the same thing as:
if bool(condition):
as far as python is concerned. Similarly for the not operator:
not condition
is the same thing as
not bool(condition)
mylist is False means "is the object named mylist exactly the same object as False?"
mylist == False means "is the object named mylist equal to False?
not mylist means "does the object named mylist behave falsily?
None of these are equivalent: 1 is not 1.0 but 1 == 1.0 and [] != False but not [] is True.
Comparing the list to False, and testing the list's truth or falsehood aren't quite the same thing. An empty list isn't equal to False, but behaves as False in a boolean context.
Here's another way to say it that might help this make sense:
print (bool([]) == False) # will print True
print ([] == False) # will print False

Categories

Resources