This may be simply idiotic, but for me it's a bit confusing:
In [697]: l=[]
In [698]: bool(l)
Out[698]: False
In [699]: l == True
Out[699]: False
In [700]: l == False
Out[700]: False
In [701]: False == False
Out[701]: True
Why does l==False return False while False == False returns True?
You are checking it against the literal value of the boolean False. The same as 'A' == False will not be true.
If you cast it, you'll see the difference:
>>> l = []
>>> l is True
False
>>> l is False
False
>>> l == True
False
>>> l == False
False
>>> bool(l) == False
True
The reason False == False is true is because you are comparing the same objects. It is the same as 2 == 2 or 'A' == 'A'.
The difficulty comes when you see things like if l: and this check never passes. That is because you are checking against the truth value of the item. By convention, all these items will fail a boolean check - that is, their boolean value will be False:
None
False (obviously)
Any empty sequence: '', [], ()
Any "zero" value: 0, 0.0, etc.
Any empty collection: {} (an empty dict)
Anything whose len() returns a 0
These are called "falsey" values. Everything else is "true". Which can lead to some strange things like:
>>> def foo():
... pass
...
>>> bool(foo)
True
It is also good to note here that methods that don't return an explicit value, always have None as their return type, which leads to this:
>>> def bar():
... x = 1+1
...
>>> bool(bar)
True
>>> bool(bar())
False
An empty list is not the same as False, but False equals False because it's the same object. bool(l) returns False because an empty list is "falsy".
In short, == is not bool() == bool().
For example, [1, 2] == [1, 2, 3] is False, even if the two are "truly".
It is because the empty list is not False, it is just "falsy" when converted to a bool, or when evaluated by the an if or while condition (which both evaluate the bool conversion of their condition). See the documentation on Truth Value Testing for more detail.
Related
I've just started learning Python and i was trying this
[] == False #False
but :
bool([]) #False
from what i got values like [],0 .. are False what did i missed exactly and thanks!
The operator == is very literal. If the 2 things you are comparing are not exactly the same (this includes types, like "2" == 2 is False) then the result will always be False. So the boolean False is not literally the same thing as an empty list [] which is why [] == False is False.
An empty list is just treated as "False" when converted to a boolean, which you did with bool([]). So the output of bool([]) is False which is literally the same as False. Thus bool([]) == False is True.
[] != False, but bool([]) == bool(False).
This may be simply idiotic, but for me it's a bit confusing:
In [697]: l=[]
In [698]: bool(l)
Out[698]: False
In [699]: l == True
Out[699]: False
In [700]: l == False
Out[700]: False
In [701]: False == False
Out[701]: True
Why does l==False return False while False == False returns True?
You are checking it against the literal value of the boolean False. The same as 'A' == False will not be true.
If you cast it, you'll see the difference:
>>> l = []
>>> l is True
False
>>> l is False
False
>>> l == True
False
>>> l == False
False
>>> bool(l) == False
True
The reason False == False is true is because you are comparing the same objects. It is the same as 2 == 2 or 'A' == 'A'.
The difficulty comes when you see things like if l: and this check never passes. That is because you are checking against the truth value of the item. By convention, all these items will fail a boolean check - that is, their boolean value will be False:
None
False (obviously)
Any empty sequence: '', [], ()
Any "zero" value: 0, 0.0, etc.
Any empty collection: {} (an empty dict)
Anything whose len() returns a 0
These are called "falsey" values. Everything else is "true". Which can lead to some strange things like:
>>> def foo():
... pass
...
>>> bool(foo)
True
It is also good to note here that methods that don't return an explicit value, always have None as their return type, which leads to this:
>>> def bar():
... x = 1+1
...
>>> bool(bar)
True
>>> bool(bar())
False
An empty list is not the same as False, but False equals False because it's the same object. bool(l) returns False because an empty list is "falsy".
In short, == is not bool() == bool().
For example, [1, 2] == [1, 2, 3] is False, even if the two are "truly".
It is because the empty list is not False, it is just "falsy" when converted to a bool, or when evaluated by the an if or while condition (which both evaluate the bool conversion of their condition). See the documentation on Truth Value Testing for more detail.
Can anyone explain this behaviour in Python (2.7 and 3)
>>> a = "Monday" and "tuesday"
>>> a
'tuesday' # I expected this to be True
>>> a == True
False # I expected this to be True
>>> a is True
False # I expected this to be True
>>> a = "Monday" or "tuesday"
>>> a
'Monday' # I expected this to be True
>>> a == True
False # I expected this to be True
>>> a is True
False # I expected this to be True
I would expect that because I am using logic operators and and or, the statements would be evaluated as a = bool("Monday") and bool("tuesday").
So what is happening here?
As explained here using and / or on strings will yield the following result:
a or b returns a if a is True, else returns b.
a and b returns b if a is True, else returns a.
This behavior is called Short-circuit_evaluation and it applies for both and, or as can be seen here.
This explains why a == 'tuesday' in the 1st case and 'Monday' in the 2nd.
As for checking a == True, a is True, using logical operators on strings yields a specific result (as explained in above), and it is not the same as bool("some_string").
Let's say I have a list with different values, like this:
[1,2,3,'b', None, False, True, 7.0]
I want to iterate over it and check that every element is not in list of some forbidden values. For example, this list is [0,0.0].
When I check if False in [0,0.0] I get True. I understand that python casts False to 0 here - but how I can avoid it and make this check right - that False value is not in [0,0.0]?
To tell the difference between False and 0 you may use is to compare them. False is a singleton value and always refers to the same object. To compare all the items in a list to make sure they are not False, try:
all(x is not False for x in a_list)
BTW, Python doesn't cast anything here: Booleans are a subclass of integers, and False is literally equal to 0, no conversion required.
You would want to use is instead of == when comparing.
y = 0
print y == False # True
print y is False # False
x = False
print x == False # True
print x is False # True
Found a weird corner case on differentiating between 0 and False today. If the initial list contains the numpy version of False (numpy.bool_(False)), the is comparisons don't work, because numpy.bool_(False) is not False.
These arise all the time in comparisons that use numpy types. For example:
>>> type(numpy.array(50)<0)
<class 'numpy.bool_'>
The easiest way would be to compare using the numpy.bool_ type: (np.array(50)<0) is (np.False_). But doing that requires a numpy dependency. The solution I came up with was to do a string comparison (working as of numpy 1.18.1):
str(numpy.bool_(False)) == str(False)
So when dealing with a list, a la #kindall it would be:
all(str(x) != str(False) for x in a_list)
Note that this test also has a problem with the string 'False'. To avoid that, you could exclude against cases where the string representation was equivalent to itself (this also dodges a numpy string array). Here's some test outputs:
>>> foo = False
>>> str(foo) != foo and str(foo) == str(False)
True
>>> foo = numpy.bool_(False)
>>> str(foo) != foo and str(foo) == str(False)
True
>>> foo = 0
>>> str(foo) != foo and str(foo) == str(False)
False
>>> foo = 'False'
>>> str(foo) != foo and str(foo) == str(False)
False
>>> foo = numpy.array('False')
>>> str(foo) != foo and str(foo) == str(False)
array(False)
I am not really an expert programmer, so there may be some limitations I've still missed, or a big reason not to do this, but it allowed me to differentiate 0 and False without needing to resort to a numpy dependency.
I would expect an empty list to value test as False, but I'm a bit confused why a reference for a list containing an object reports as False also when value tested as in the following example:
>>> weapon = []
>>> weapon == True
False
>>> weapon.append("sword")
>>> weapon == True
False
>>> weapon
['sword']
If weapon = [] is False, why would weapon = ['sword'] also be False? According to docs http://docs.python.org/release/2.4.4/lib/truth.html, it should be True. What am I missing in my understanding of this?
you should do a check like
In [1]: w = []
In [2]: if w:
...: print True
...: else:
...: print False
...:
False
When you do:
w = []
if w:
print "Truthy"
else:
print "Falsy"
the key thing to note is that whatever you are testing in the if clause is coerced to a boolean. To make it explicit:
w = []
if bool(w):
print "Truthy"
else:
print "Falsy"
To compare apples to apples then you don't want to compare ["sword"] to True. Instead you want to compare bool(["sword"]) to True:
bool(["sword"]) == True
# True
You need to use bool() if you want to compare it directly
>>> weapon = []
>>> bool(weapon) == True
False
>>> weapon.append("sword")
>>> bool(weapon) == True
True
When you test a condition using if or while, the conversion to bool is done implicitly
>>> if weapon == True: # weapon isn't equal to True
... print "True"
...
>>> if weapon:
... print "True"
...
True
From that article, note that even things are considered to have a "true" truth value, they are not necessarily == True. For example:
["hi"] == True
// False
if ["hi"]:
print("hello")
// prints hello
The documentation says "Any object can be tested for truth value" not that [] == False or ['whatever'] == True. You should test objects as specified in the documentation "for use in an if or while condition or as operand of the Boolean operation".