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".
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.
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 stumbled upon this apparently horrific piece of code:
def determine_db_name():
if wallet_name in "":
return "wallet.dat"
else:
return wallet_name
What is supposed if xx in "": to mean? Doesn't it always evaluates to False?
It'll return True if wallet_name is itself empty:
>>> foo = ''
>>> foo in ''
True
It is horrific though. Just use if not wallet_name: instead, or use or and do away with the if statement altogether:
def determine_db_name():
return wallet_name or "wallet.dat"
which works because or short-circuits, returning wallet_name if it is not the empty string, otherwise "wallet.dat" is returned.
That expression is true if wallet_name is the empty string.
It would probably be clearer if the code had been written as follows:
if wallet_name == '':
Or just:
if not wallet_name:
Usually in is used when checking if a key exists in an array or an element exists in a list.
>>> 2 in [1,2,3]
True
>>> 6 in [1,2,3]
False
>>> 'foo' in {'bar', 'foo', 'baz'}
True
But it works for strings as well:
>>> 'foo' in 'barfoobar'
True
>>> 'foo' in 'barbarbar'
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.