How to test if a value is falsy in Python 3 - python

In Javascript, there is == operator to test if a value is falsy:
'' == false // true
In Python, == corresponds to === in Javascript, which is an exact equation (value & type).
So how to find out if a value is Falsy in Python?

You can obtain the truthiness of a value, by using the bool(..) function:
>>> bool('')
False
>>> bool('foo')
True
>>> bool(1)
True
>>> bool(None)
False
In an if statement, the truthiness is calculated implicitly. You can use the not keyword, to invert the truthiness. For example:
>>> not ''
True
>>> not 'foo'
False
>>> not 1
False
>>> not None
True

To get implicit conversion you can just use not - or (for "truthy") just use the variable in place:
if not None:
print('None')
if not False:
print('False')
if not '':
print('empty string')
if not 0:
print('zero')
if not {}:
print('empty/zero length container')
if 'hello':
print('non empty string, truthy test')

What worked was using ternary:
True if '' else False # False
More verbose than in Javascript, but works.

Even tho this question is old, but there is a not not (kinda hacky), but this is the faster than bool(..) and probably the fastest that's possible, you can do it by:
print(not not '')
print(not not 0)
print(not not 'bar')
Output:
False
False
True

Related

Understanding precedence of `not` operator [duplicate]

This question already has answers here:
Priority of the logical operators (order of operations) for NOT, AND, OR in Python
(8 answers)
Closed 2 years ago.
I tried to test empty string in Python (empty string should be "Falsy" as they write in: How to check if the string is empty?). However I used a little bit different syntax and get weird result in the following comparison:
not(''); # result: True
not('hello'); # result: False
not('hello') == False; # result: True
not('hello') == True; # result: True - how is this result possible? (False == True: result must be False)
Thank you for the answer!
The precedence here is not ('hello' == False). 'hello' equals neither True nor False, so both 'hello' == True and 'hello' == False are False, which is then negated by not.
>>> 'hello' == False
False
>>> 'hello' == True
False
>>> not ('hello' == True)
True
Truthiness isn't the same as being equal to True. A string can be truthy (i.e. you can decide whether it's more of a "yes" or a "no"), but at the same time not be equal to a boolean value (because a string is a string and a boolean is a boolean).
It's important to understand that not is an operator, not a function. The parenthesis do nothing for the expression, here's how it is read:
not('hello') == True
# is the same as
not 'hello' == True
# which is the same as
not ('hello' == True)
# which is equivalent to
not False
# which is
True
Which happens to evaluate to the same as the expression above (for the same reason that 'hello' == False is False.
The correct way of enforcing precedence with not would be to do
(not something) == True

Weird behaviour of `not` operator with python list

When I'm trying to check whether a list is empty or not using python's not operator it is behaving in a weird manner.
I tried using the not operator with a list to check whether it is empty or not.
>>> a = []
>>> not (a)
True
>>> not (a) == True
True
>>> not (a) == False
True
>>> True == False
False
The expected output for not (a) == False should be False.
== has higher precedence than not. not (a) == False is parsed as not (a == False).
This is working as expected. Parenthesis added below to clarify how this is being executed:
not (a == True)
# True
not (a == False)
# True
An empty list, a = [], evaluates to False in boolean expressions, but it does not equal False or True. Your expressions in the middle are testing whether it is equal to False or True, so they both evaluate to False, and not False is True.
You can add parenthesis like below to get what you expect:
(not a) == True
# True
(not a) == False
# False

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

Returning the truthiness of a variable rather than its value?

Consider this code:
test_string = 'not empty'
if test_string:
return True
else:
return False
I know I could construct a conditional expression to do it:
return True if test_string else False
However, I don't like testing if a boolean is true or false when I'd rather just return the boolean. How would I just return its truthiness?
You can use bool:
return bool(test_string)
Demo:
>>> bool('abc')
True
>>> bool('')
False
>>>

Convert True/False value read from file to boolean

I'm reading a True - False value from a file and I need to convert it to boolean. Currently it always converts it to True even if the value is set to False.
Here's a MWE of what I'm trying to do:
with open('file.dat', mode="r") as f:
for line in f:
reader = line.split()
# Convert to boolean <-- Not working?
flag = bool(reader[0])
if flag:
print 'flag == True'
else:
print 'flag == False'
The file.dat file basically consists of a single string with the value True or False written inside. The arrangement looks very convoluted because this is a minimal example from a much larger code and this is how I read parameters into it.
Why is flag always converting to True?
bool('True') and bool('False') always return True because strings 'True' and 'False' are not empty.
To quote a great man (and Python documentation):
5.1. Truth Value Testing
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:
…
zero of any numeric type, for example, 0, 0L, 0.0, 0j.
any empty sequence, for example, '', (), [].
…
All other values are considered true — so objects of many types
are always true.
The built-in bool function uses the standard truth testing procedure. That's why you're always getting True.
To convert a string to boolean you need to do something like this:
def str_to_bool(s):
if s == 'True':
return True
elif s == 'False':
return False
else:
raise ValueError # evil ValueError that doesn't tell you what the wrong value was
you can use distutils.util.strtobool
>>> from distutils.util import strtobool
>>> strtobool('True')
1
>>> strtobool('False')
0
True values are y, yes, t, true, on and 1; False values are n, no, f, false, off and 0. Raises ValueError if val is anything else.
Use ast.literal_eval:
>>> import ast
>>> ast.literal_eval('True')
True
>>> ast.literal_eval('False')
False
Why is flag always converting to True?
Non-empty strings are always True in Python.
Related: Truth Value Testing
If NumPy is an option, then:
>>> import StringIO
>>> import numpy as np
>>> s = 'True - False - True'
>>> c = StringIO.StringIO(s)
>>> np.genfromtxt(c, delimiter='-', autostrip=True, dtype=None) #or dtype=bool
array([ True, False, True], dtype=bool)
The cleanest solution that I've seen is:
from distutils.util import strtobool
def string_to_bool(string):
return bool(strtobool(str(string)))
Sure, it requires an import, but it has proper error handling and requires very little code to be written (and tested).
I'm not suggested this as the best answer, just an alternative but you can also do something like:
flag = reader[0] == "True"
flag will be True id reader[0] is "True", otherwise it will be False.
Currently, it is evaluating to True because the variable has a value. There is a good example found here of what happens when you evaluate arbitrary types as a boolean.
In short, what you want to do is isolate the 'True' or 'False' string and run eval on it.
>>> eval('True')
True
>>> eval('False')
False
If you want to be case-insensitive, you can just do:
b = True if bool_str.lower() == 'true' else False
Example usage:
>>> bool_str = 'False'
>>> b = True if bool_str.lower() == 'true' else False
>>> b
False
>>> bool_str = 'true'
>>> b = True if bool_str.lower() == 'true' else False
>>> b
True
You can use dict to convert string to boolean. Change this line flag = bool(reader[0]) to:
flag = {'True': True, 'False': False}.get(reader[0], False) # default is False
pip install str2bool
>>> from str2bool import str2bool
>>> str2bool('Yes')
True
>>> str2bool('FaLsE')
False
If your data is from json, you can do that
import json
json.loads('true')
True
You can do with json.
In [124]: import json
In [125]: json.loads('false')
Out[125]: False
In [126]: json.loads('true')
Out[126]: True
Just to add that if your truth value can vary, for instance if it is an input from different programming languages or from different types, a more robust method would be:
flag = value in ['True','true',1,'T','t','1'] # this can be as long as you want to support
And a more performant variant would be (set lookup is O(1)):
TRUTHS = set(['True','true',1,'T','t','1'])
flag = value in truths
Unfortunately, strtobool is now deprecated.
Here is an implementation based on configparser which you can use instead of your bool:
import configparser
def strtobool(s):
try:
return configparser.ConfigParser.BOOLEAN_STATES[s.lower()]
except KeyError as e:
raise ValueError('Not a boolean: %s' % s) from e
If you need quick way to convert strings into bools (that functions with most strings) try.
def conv2bool(arg):
try:
res= (arg[0].upper()) == "T"
except Exception,e:
res= False
return res # or do some more processing with arg if res is false
Using dicts to convert "True" in True:
def str_to_bool(s: str):
status = {"True": True,
"False": False}
try:
return status[s]
except KeyError as e:
#logging
If you have
>>> my_value = "False"
then either do
>>> my_value in "False"
True
>>> my_value in "True"
False
or
>>> "False" in my_value
True
>>> "True" in my_value
False
def strtobool(val):
"""Convert a string representation of truth to true (1) or false (0).
True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if
'val' is anything else.
"""
val = val.lower()
if val in ('y', 'yes', 't', 'true', 'on', '1'):
return True
elif val in ('n', 'no', 'f', 'false', 'off', '0'):
return False
else:
raise ValueError("invalid truth value %r" % (val,))
Ternary operator one-liner:
var_x = True if str_x == 'True' else False

Categories

Resources