97

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?

Gabriel
  • 40,504
  • 73
  • 230
  • 404

18 Answers18

118

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
kev
  • 8,928
  • 14
  • 61
  • 103
Nigel Tufnel
  • 11,146
  • 4
  • 35
  • 31
  • 29
    You could make it a "heroic" `ValueError` by doing `raise ValueError("Cannot covert {} to a bool".format(s))`. – SethMMorton Feb 12 '14 at 15:45
  • Selecting this one since it uses no extra packages. Thanks guys! – Gabriel Feb 12 '14 at 17:05
  • 1
    What's wrong with "extra packages"? Are you referring to `ast`? It's part of the standard library, so it's not really extra. – SethMMorton Feb 12 '14 at 17:13
  • 5
    it might be a silly question but why does `bool` just not convert the strings `True` and `False` to the boolean values `True` and `False`? Seems to be inconsistent behaviour from what `int` does. I just genuinely curious why my reasoning is wrong and why the other option was the decision. – Charlie Parker Jul 30 '16 at 00:54
  • 2
    Whenever comparing strings I like to flatten the case, (where applicable). for example I would use: if s.upper() == 'TRUE': return True elif s.upper() == 'FALSE' return False – Bill Kidd Aug 03 '16 at 12:21
91

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.

Francesco Nazzaro
  • 2,688
  • 11
  • 20
62

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)
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • it might be a silly question but why does `bool` just not convert the strings `True` and `False` to the boolean values `True` and `False`? Seems to be inconsistent behaviour from what `int` does. I just genuinely curious why my reasoning is wrong and why the other option was the decision. – Charlie Parker Jul 30 '16 at 00:55
  • 2
    ast.literal_eval('false') throws an exception, which I think makes it less desirable – Chris Feb 02 '18 at 05:19
  • @Chris You can always wrap it around try-except in a custom function instead of using it directly then. – Ashwini Chaudhary Feb 02 '18 at 07:29
  • @HewwoCraziness It parses only expressions not any random code. – Ashwini Chaudhary Sep 05 '19 at 18:03
22

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

vpetersson
  • 1,630
  • 2
  • 17
  • 18
  • 1
    This doesn't work unless the input value can actually be a boolean, otherwise, it seems to throw a value error. The only thing I can think of is to add a try/except to your function and on `ValueError` return false. – Ari Nov 20 '20 at 05:57
15

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.

elParaguayo
  • 1,288
  • 1
  • 13
  • 24
15

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
Adam Hopkins
  • 6,837
  • 6
  • 32
  • 52
Gautam Joshi
  • 317
  • 2
  • 4
  • 6
    @samyi It is dangerous to use the eval method. http://stackoverflow.com/questions/1832940/is-using-eval-in-python-a-bad-practice – M07 Jan 10 '17 at 21:27
  • 3
    FYI. This is a terrible idea and you should *never* use `eval()`. In my opinion, it should be removed from the language. – Nostalg.io Feb 16 '18 at 18:37
  • 2
    This is VERY VERY BAD because it is a security flaw. If you use `eval()` on raw data from a file then it means that anyone with write access to that file can execute code at the same permissions level as your script. – Keith Ripley Apr 03 '18 at 22:56
  • 1
    Additionally, if values have not the exact python spelling, e.g. `eval('false')`, `eval('FALSE')` it will error. – kev Apr 11 '18 at 01:23
9

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
caleb
  • 2,687
  • 30
  • 25
5

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
ndpu
  • 22,225
  • 6
  • 54
  • 69
5

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
Rahul K P
  • 15,740
  • 4
  • 35
  • 52
  • This gives a JSON Decode Error when the string is 'True' or 'False' i.e. title-format. Use json.loads('False'.lower) in that case. – Ben Feb 08 '22 at 17:45
4

pip install str2bool

>>> from str2bool import str2bool
>>> str2bool('Yes')
True
>>> str2bool('FaLsE')
False
Symon
  • 1,626
  • 1
  • 23
  • 31
4

If your data is from json, you can do that

import json

json.loads('true')

True

4

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
Daniel Dror
  • 2,304
  • 28
  • 30
2

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
Bharel
  • 23,672
  • 5
  • 40
  • 80
0

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

user6830669
  • 161
  • 4
0

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
chris
  • 742
  • 5
  • 7
0

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
Boštjan Mejak
  • 827
  • 9
  • 23
0
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,))
0

Ternary operator one-liner:

var_x = True if str_x == 'True' else False
j4n7
  • 590
  • 7
  • 9