Converting from a string to boolean in Python?

225

Solution 1

Really, you just compare the string to whatever you expect to accept as representing true, so you can do this:

s == 'True'

Or to checks against a whole bunch of values:

s.lower() in ['true', '1', 't', 'y', 'yes', 'yeah', 'yup', 'certainly', 'uh-huh']

Be cautious when using the following:

>>> bool("foo")
True
>>> bool("")
False

Empty strings evaluate to False, but everything else evaluates to True. So this should not be used for any kind of parsing purposes.

Solution 2

Use:

bool(distutils.util.strtobool(some_string))

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.

Be aware that distutils.util.strtobool() returns integer representations and thus it needs to be wrapped with bool() to get Boolean values.

Solution 3

def str2bool(v):
  return v.lower() in ("yes", "true", "t", "1")

Then call it like so:

>>> str2bool("yes")
True
>>> str2bool("no")
False
>>> str2bool("stuff")
False
>>> str2bool("1")
True
>>> str2bool("0")
False

Handling true and false explicitly:

You could also make your function explicitly check against a True list of words and a False list of words. Then if it is in neither list, you could throw an exception.

Solution 4

The JSON parser is also useful for in general converting strings to reasonable python types.

>>> import json
>>> json.loads("false".lower())
False
>>> json.loads("True".lower())
True

Solution 5

Starting with Python 2.6, there is now ast.literal_eval:

>>> import ast
>>> help(ast.literal_eval)
Help on function literal_eval in module ast:

literal_eval(node_or_string)
    Safely evaluate an expression node or a string containing a Python
    expression.  The string or node provided may only consist of the following
    Python literal structures: strings, numbers, tuples, lists, dicts, booleans,
    and None.

Which seems to work, as long as you're sure your strings are going to be either "True" or "False":

>>> ast.literal_eval("True")
True
>>> ast.literal_eval("False")
False
>>> ast.literal_eval("F")
Traceback (most recent call last):
  File "", line 1, in 
  File "/opt/Python-2.6.1/lib/python2.6/ast.py", line 68, in literal_eval
    return _convert(node_or_string)
  File "/opt/Python-2.6.1/lib/python2.6/ast.py", line 67, in _convert
    raise ValueError('malformed string')
ValueError: malformed string
>>> ast.literal_eval("'False'")
'False'

I wouldn't normally recommend this, but it is completely built-in and could be the right thing depending on your requirements.

Share:
225
zsss
Author by

zsss

Updated on July 15, 2022

Comments

  • zsss
    zsss almost 2 years

    Can somebody help me with sinegy API signature? This is what they are asking:

    API methods that use full signed authentication requires api-key in the request header and api-signature in the request body.

    API signature is an encoded message which contains:

    Stringed request parameters
    Method of API function
    Path of API function
    API secret

    These attributes must be separated by the vertical line | delimiter, hashed in HMAC-SHA25, and encoded in base64 format.

    I don't have any experience with API signatures, this is what I tried so far:

    secret = '$KDcKdsemlwJ6Vmj05f5NOQ4e.'
    
    digest = hmac.new(
        secret.encode(),
        'ghjfghjfgh|fjkghkghj|ghjkghjk|ljklhjklh'.encode(),
        hashlib.sha256
    )
    signature = base64.b64encode(digest.digest())
    

    This is what their example signature looks like: 8asufaol53wad, but what I receive is: b'qCTV/psNaUdZt/F+0QMhDISb/n4yYuYrK7YG8aMCC7U='

    Here is their full API doc: https://docs.sinegy.com/#tag/Authentication

  • user1066101
    user1066101 about 15 years
    +1: Not much could be simpler than s == "True". But I've seen people make a real mess of this. def convert(s): if s == "True": return True; return False.
  • user1066101
    user1066101 about 15 years
    What is the val = "false" line doing on this example? Why is it there? What does it mean?
  • Dana
    Dana about 15 years
    I prefer return s == "True" over the if/else
  • user1066101
    user1066101 about 15 years
    @Dana: everyone should. if x: return True is a terrible thing. The only thing worse is if x: return False.
  • SingleNegationElimination
    SingleNegationElimination almost 15 years
    Not sure of the general applicability of this solution, but it's very nice, in a general sort of way. +1!
  • Unknown
    Unknown almost 15 years
    if s == "True": return True elif s=="False": return False else: return raise
  • SilentGhost
    SilentGhost over 14 years
    it's better to use sets, not in and your selection of false items is somewhat idiosyncratic.
  • estani
    estani over 11 years
    You are missing the false part. False is not the same as "not True" when parsing, as you will be parsing all errors to false.
  • jkh
    jkh over 11 years
    I think you're missing the point: the point of the answers was to demonstrate the general principle, not to tell person who asked the question exactly how they should do it. The person who asked the question originally was overthinking what's actually a simple problem.
  • jkh
    jkh over 11 years
    @estani: No, I didn't miss the false part. You're missing the point of my answer, which was to demonstrate the basic principle of simply checking if the string provided is amongst the valid values. You'll notice that I didn't provide a function to do the complete job: that was on purpose.
  • estani
    estani over 11 years
    @Keith don't take it wrong, but I still think that in order to answer the question posted here, you need to clarify that when parsing a string, you should parse both values and fail otherwise. IMHO you are missing the point of the question.
  • estani
    estani over 11 years
    @Keith I disagree. The point is answering the question as it is asked.
  • jkh
    jkh over 11 years
    The question asked was how to convert a string to a boolean. That was the question I answered. I have no idea what's considered a valid boolean string for the original poster, and nor do you. That's why it's more important to demonstrate the general principle than give the poster the full answer. The original poster didn't need everything spelled out to them: all they needed was for the general principle to be demonstrated. From that, anybody competent will get to your answer.
  • estani
    estani over 11 years
    @Keith not sure what this is all about but the point is building knowledge. I'm not "judging" your answer, I fell no other answer was "complete" as they missed the fact that parsing a boolean has 3 outcomes, true, false or unparsable. That's all. (I will just pretend I never read the last line of your comment)
  • Rafael T
    Rafael T about 11 years
    One could get bitten by this: to_bool(["hello"]) which should be a perfectly valid call, if [] is supported
  • Petrucio
    Petrucio about 11 years
    Returns "Exception: Invalid value for boolean conversion: ['hello']", which is expected and documented. In my opinion an empty list was clearly a false, but ['false'] wasn't clearly anything, so I left it out intentionally - that's a feature not a bug. Should be easy to add support for returning true for non-empty lists if that's what you want.
  • Rafael T
    Rafael T about 11 years
    shure you documented it. But in real live one would never call to_bool([]). Instead he would do something along these lines: myList=someFunctionThatReturnAList `if (is_bool(myList)):...´ so one have a list and want to know if this list is None or empty.
  • ThePracticalOne
    ThePracticalOne almost 11 years
    Why not try this: >>> def a2b(arg): ... default = bool(arg) ... if isinstance(arg, str): ... return arg.lower() in ['true', 't', 'yes', 'y', '1'] ... else: ... return default
  • jzwiener
    jzwiener almost 11 years
    Parsing strings to booleans is already implemented in distutils.util.strtobool: stackoverflow.com/a/18472142/923599
  • jkh
    jkh almost 11 years
    Yeah, I know about that, and it's possibly one of the oddest places to put something like that. In fact, that whole module is a grab-bag of stuff that would be better off elsewhere, and that's one of the reasons I don't use it: that whole module is the kind of thing that's likely to be deprecated at some point in the future.
  • jkh
    jkh almost 11 years
    That's functionally equivalent to, and more complex than: return value in ('True', 'true')
  • Vanessa Phipps
    Vanessa Phipps over 10 years
    Gaah, that's horrifying! Then again, you did say you don't recommend it, and it does answer the question neatly. Good find!
  • Bhushan
    Bhushan about 10 years
    Unfortunately it doesn't handle this case >>>ast.literal_eval('true') or ast.literal_eval('TRUE') Raises >>> raise ValueError('malformed string') The fix is simple though ast.literal_eval(to_test.title())
  • travc
    travc over 9 years
    Not a great solution to this particular question, but... Wow, literal_eval is damn useful! String to list, dict, ect.
  • MarkHu
    MarkHu over 9 years
    That function is tantalizing. It would be perfect if it handled integers and None and str(None) as input.
  • Anentropic
    Anentropic over 9 years
    apparently you should use a set rather than list for the truthy strings... stackoverflow.com/a/7110296/202168
  • Anentropic
    Anentropic over 9 years
    I much prefer this to the higher voted answers... it's from stdlib and does exactly what's required. There is generally no reason to need an actual bool instead of 1/0 as long as you're not doing bad stuff like if x == False... and if you're dealing with ints and Nones you don't need a special function, you can just check them directly if myint: or if not maybe_none_var:
  • Anentropic
    Anentropic over 9 years
    @Secator bool is a sub-class of int
  • jkh
    jkh over 9 years
    That depends. For something very short, it can be faster to scan a list or tuple. It's a trade-off between the length of time it takes to scan the list/tuple vs the time taken to hash the object look it up, and you also have to factor in the time needed to create the set object itself. It's not something I'd worry about too much unless it's really something that needs optimising. Profile, then optimise.
  • kmonsoor
    kmonsoor over 9 years
    little enhancement can be made using, str(v).lower() instead of v.lower(). Then, it can work even it is not string, e.g. 1, 0
  • dshepherd
    dshepherd about 9 years
    Minor point: you should probably prefer ValueError over a plain Exception.
  • dshepherd
    dshepherd about 9 years
    Do you need the isinstance check? I would think that duck typing suffices: anything with method .lower() which compares equal to one of the given strings is almost certainly some kind of string.
  • estani
    estani about 9 years
    @dshepherd the isinstance is there to be sure I'm parsing what I expect. I'm parsing strings so a method car_race.lower() that by chance returns '1' shouldn't return true, it should throw a ValueError. But it might suffice in other cases.
  • CivFan
    CivFan about 9 years
    The elif can be (and should be IMHO) simplified to if. Not sure if there's a PEP style guide on this, but using if correctly implies that your code is doing an assert style return, for lack of a better phrase. elif here implies you need it to be elif, when you don't.
  • estani
    estani about 9 years
    @CivFan interesting point. Though I tried it, and it didn't read so nice (to me). elif is redundant because of the return word, but it gives you more information without having to scan for return. But that's only me, if there's a PEP style violation, I would change it though. Without any other constrain, we should always go for readability (and standards do that). Thanks for the heads up and interesting comment!
  • praxmon
    praxmon over 8 years
    Does it work on unicodes to? In my Django view I have an incoming value which I want to change to boolean, it is giving a malformed string exception.
  • jpmc26
    jpmc26 over 8 years
    @RafaelT Actually, I imagine they would be more likely to do if my_list: than if to_bool(my_list):. I do tend to agree that trying to support list and dict is probably a bad idea. I can't actually leverage that support unless I already know it is empty because a non-empty one will throw an error, but if I already know that, I don't even need this function. The other asymmetries are a bit iffy, too. The string 'NONE' is converted to False (inconsistent with normal Python), and supporting the float 0.0 has a lot of the same problems as list/dict.
  • Johnus
    Johnus over 8 years
    RE: handling true/false explicitly, you could also provide a default value if the string isn't matched, much like how true/false command-line prompts work: Continue? (y/N)
  • Ev.
    Ev. over 7 years
    I know this is a REALLY old topic, but I wanted to attest that I have just spent 4 hours trying to debug my code. My mistake was trying to cast bool("False"). It will always cast to True.
  • Taylor D. Edmiston
    Taylor D. Edmiston over 7 years
    You actually don't need the if s else False bit. Think about how "False" == "True" will already return False.
  • jimh
    jimh over 7 years
    this exactly what I was looking for, evaluating an input field from a file and based on the outcome storing a boolean. thank you.
  • augurar
    augurar about 7 years
    Nit: Your last "test case" will error out on the first call and not test the others. Also, it will not fail if an error is not raised.
  • pppery
    pppery about 7 years
    Use str instead of type('')
  • kontur
    kontur over 6 years
    If you are unsure if the input s is a string or already a boolean, you can add if type(s) is bool: return s.
  • mastov
    mastov over 6 years
    What happens, if the string contains #\nshutil.rmtree('/someImportantDirectory')? (Don't try it!)
  • elPastor
    elPastor over 6 years
    @mastov - ridiculous downvote. Obviously if you don't have control of the incoming string, you need to put precautions in place, as you would with any code. But if you do control the workflow, this is a simple solution that works. Don't confuse a solution that isn't perfect in every way with a bad answer.
  • mastov
    mastov over 6 years
    Apart from not mentioning the dangers (which already makes this a bad answer): You are proposing to sanitize the input beforehand? That's going to kill the simplicity of this method, which was its main plus.
  • mastov
    mastov over 6 years
    Using eval for something this simple is just asking for a vulnerability.
  • elPastor
    elPastor over 6 years
    Not all code is exposed to the general public, and thus not susceptible to the issues that seem to frighten you so much. A simple comment that this answer should include a warning would suffice.
  • mastov
    mastov over 6 years
    Not all code. But especially code that converts strings to other types usually is out of your control. Often you might not even realize it. You might say: "It's my database (or config file), it's part of my system, under my control." Then you give some other module access to a database because: "What's the harm? It's only some tables with strings." But with eval those strings might help someone to take over the whole system.
  • Overcode
    Overcode about 6 years
    @pshep123 The security part isn't even the only concern. Using eval to convert a string to a boolean is just beyond bad practice. There are proper ways to do things, which definitely don't include using the jackhammer that is eval to hammer in a nail. The (non ridiculous) downvote isn't because your answer doesn't work - it's because it's a bad answer, even if it does work.
  • elPastor
    elPastor about 6 years
    @Overcode, to say anything "is just beyond bad practice" and not giving a reason (especially when ruling out security issue) is beyond bad practice. Help us learn why things are bad practice instead of just saying that they are.
  • Overcode
    Overcode about 6 years
    @pshep123 If you are really interested, a quick google of "why is eval bad" should give you plenty to read. Code injection violates the Fundamental Principle of Software. On top of that, eval is slower (you force the interpreter to revisit the precompiler), harder to debug, displays bad code design, etc. And just like in this situation, there's almost always just a better way to do it that fits good code design/practice.
  • elPastor
    elPastor about 6 years
    Good to know. Thanks.
  • Peter Wood
    Peter Wood almost 6 years
    The yaml module is a third party library: PyYAML
  • nurettin
    nurettin over 5 years
    that string will come from somewhere. if eval(os.environ["LOL"]): #might never reach here. Might also charge your company's credit card.
  • S. de Melo
    S. de Melo over 5 years
    How is it more succinct than my_string == 'True'?
  • Joel Croteau
    Joel Croteau over 5 years
    @nurettin, hence my comment about only using it if you're sure of the contents of the string.
  • user2023861
    user2023861 almost 5 years
    I suggest adding the boolean True in your list of true values. This way if s was already converted to a boolean previously, the result will be True instead of False. s in ['true', '1', 't', 'y', 'yes', 'yeah', 'yup', 'certainly', 'uh-huh', True]
  • ely
    ely almost 5 years
    I'll add a dissenting opinion on this one. This is an issue with Python design, not users overcomplicating things. It bools down to a case when type safety is sincerely needed. Checking s == 'True' is a bad way to solve it because the type of s can be anything, and people are free to implement screwball overrides of equality checking. To be safe then, you have to start putting in assert statements and attempts to do type casting before the equality check and very quickly you can sympathize with what @S.Lott calls "a real mess" because the naive 'easy' way often breaks.
  • jkh
    jkh almost 5 years
    @ely Your complaint boils down to "Python is dynamically typed, and that's bad". @S.Lott's note had nothing to do with type safety, but that people use unnecessary if-statements. s == 'True' evaluates to a boolean object, so including an if-statement whose clauses are return True and return False is an overcomplication.
  • ely
    ely almost 5 years
    @KeithGaughan you are incorrect. I happen to love Python's dynamic typing and have used it happily for many years. But we can't have rose colored glasses to the fact that some aspects of Python are designed badly. On your last point I think you misunderstood my comment. I totally understand the extra return True type thing is strictly not needed, I am saying that using s == 'True' is bad for a bunch of reasons and so people don't use s == 'True' in practice and end up needing lots of other complications like my_converter_func(s) is True where my_converter_func really is needed.
  • jkh
    jkh almost 5 years
    @ely I think you're misunderstanding my point, and the point @S.Lott was making. Maybe if I phrase it in terms of Java rather than Python, it'll make more sense. We were saying that writing something like bool isOdd(int n) { if (n % 2 == 1) { return true; } else { return false; }} is bad when you can just write bool isOdd(int n) { return n % 2 == 1; }. Your stuff about types was irrelevant to the point. Also, your 'badly designed' stuff is true of every dynamically typed language, and Python is less 'bad' than most because it's also strongly typed.
  • ely
    ely almost 5 years
    @KeithGaughan I encourage you to re-read my comments. The specific details about an extraneous return True when you could just return the evaluation of the boolean condition itself ... that is not related to my comment or to the original from S.Lott that I was responding to. That's just some ancillary detail about one particular inefficient way to deal with it in novice implementations, and is not related at all to the bigger point.
  • jkh
    jkh almost 5 years
    @ely, I fail to see the point you're trying to make. 'the type of s can be anything' is a consequence of Python being dynamically typed. I fail to see how your comments relate to anything @S.Lott wrote. What exactly is it that makes s == 'True' bad? What's the context? If one is reading from a configuration file and checking if a field contains a boolean token, something like this would be fine. I mean, you can do 'stringly typing' in just about any language. Are you saying the strings 'true' and 'false' should be treated as booleans? I'm not clear what point you're trying to make.
  • Moot
    Moot over 4 years
    Note that using a set instead of a list as done in this answer, seems to make it much faster... This is based on both timing this operation as well as the time complexity: wiki.python.org/moin/TimeComplexity
  • Edward B.
    Edward B. about 4 years
    To save someone some Googling of errors: import distutils and import distutils.util for this to work.
  • BLang
    BLang about 4 years
    This answer is really nice when trying to interpret environment variables since they get passed in as string, you can just use my_var = os.environ["MY_ENV_VAR"]=="True"
  • Martin Braun
    Martin Braun almost 4 years
    wow, for anyone finding this: do NOT use this for anything else than simple scripts. If you use this in any serious application you will open yourself up to all kinds of unwanted code execution. Imagine a scenario where you parse input from a user and to convert a string to a boolean you use this. In this scenario an attacker can basically do anything that your code does. Don't trust me? Try this: import os eval("os.getcwd()")
  • Roel
    Roel almost 4 years
    @MartinBraun Ah yes study finds that you can execute this eval('os.system(‘rm -rf /’)') and it deletes all the files in that directory. However eval() are perfectly OK for a trusted code it is not really evil. So I better put a note to be careful.
  • Darren Weber
    Darren Weber almost 4 years
    Add s.strip().lower() to trim excess whitespace.
  • Darren Weber
    Darren Weber almost 4 years
    Add a some_string.strip() to remove excess whitespace or it can throw a ValueError.
  • jkh
    jkh almost 4 years
    You could add that too and, in a real-world situation to clean up the input, should, but it's tangential to the point I'm trying to make, which is not to complicate things and just use comparisons.
  • slajma
    slajma over 3 years
    please please please, there are a LOT safer options above, why would you want to use eval for a simple string comparison you can never be 100% certain that a piece of code is going to stay the same and behave the same over time but there's a slight chance that you leave the eval in there then the disaster soup is ready
  • and1er
    and1er over 3 years
    If import distutils.util fails with AttributeError: module 'distutils' has no attribute 'util', following statement could help: from distutils.util import strtobool. It is strange but I met this situation at one.
  • WestCoastProjects
    WestCoastProjects over 3 years
    so much work just to convert to boolean? really?
  • Kris M
    Kris M over 3 years
    This is the correct answer I was googling for. eval("True") = True and eval("False") = False. Simple. I use it to ping a config file for booleans.
  • Sigmatics
    Sigmatics over 3 years
    Here is a good overview of values that will yield False: w3schools.com/python/python_booleans.asp False, None, 0, "", (), [], {}
  • aasmpro
    aasmpro over 3 years
    Such a great one. tnx.
  • ely
    ely about 3 years
    @KeithGaughan Just coming back to this thread. I still feel you missed the point of my examples. The key point is that s == 'True' hinges on the definition of __eq__, so it's not in general safe to compare with a string on the RHS. That's not "a consequence of dynamic typing" - it's a consequence of Python's data model. Because someone might need to compare s with 'True', and they can't control what type s is or how __eq__ may have been overridden, it virtually always necessitates using formatters / validators as helpers, like some_converter_func(s) is True, to "handle" __eq__
  • jkh
    jkh about 3 years
    @ely I didn't miss anything in your examples. If you have your own answer you want to post, post your own answer.
  • ely
    ely about 3 years
    @KeithGaughan the main thing is just to ensure there is a strong signal about the pitfall for relying on __eq__ in this answer. It's a perfectly fine answer as long as that caveat is noted strongly, as in these comments.
  • jkh
    jkh about 3 years
    @ely I'm not seeing the need. Look, this answer is ten years old. If you feel like there could be a better answer, feel free to write your own rather than trying to debate with me.
  • dreftymac
    dreftymac about 3 years
    for more security against untrusted input yaml.safe_load instead of yaml.load
  • Dr_Zaszuś
    Dr_Zaszuś over 2 years
    What would be your list of False booleans equivalent to s.lower() in ['true', '1', 't', 'y', 'yes', 'yeah', 'yup', 'certainly', 'uh-huh'] ? :)
  • xjlin0
    xjlin0 over 2 years
    Unfortunately title() will capitalize every key in the object such as ast.literal_eval('{"hi": true}'.title()) to {"Hi": True}. Another way is to use from rest_framework.utils import json and then json.loads('{"hi": true}')
  • jan-di
    jan-di over 2 years
    Be aware, that the distutils package is deprecated since python 3.10 and will be removed in version 3.12.
  • jan-di
    jan-di over 2 years
    Be aware, that the distutils package is deprecated since python 3.10 and will be removed in version 3.12.
  • jkh
    jkh over 2 years
    @Dr_Zaszuś That's entirely up to you and what you expect to be treated as False.
  • Joel Croteau
    Joel Croteau over 2 years
    @KrisM, please make sure you trust the source of that config file. Any Python code you put into an eval will be executed, so it is a potential entry point for malicious code, or even just badly-formed code to get into your system.
  • BlakBat
    BlakBat over 2 years
    The extra bool_flag variable is so useless
  • ARHAM RUMI
    ARHAM RUMI over 2 years
    @BlakBat How? Can you explain why it is useless?
  • BlakBat
    BlakBat over 2 years
    Just return the value: if s == "False": return False. etc.
  • sagi
    sagi about 2 years
    and what if a = '0' ?
  • sagi
    sagi about 2 years
    does not solve the problem that the string might be "0". >>> type(ast.literal_eval("0".title())) <class 'int'>
  • John Crawford
    John Crawford about 2 years
    To expand @jan-di 's comment, distutils.util.strtobool is explicitly called out in PEP 632 as not getting an equivalent implementation in Python 3.12: > For these functions, and any others not mentioned here, you will need to reimplement the functionality yourself. The legacy documentation can be found at docs.python.org/3.9/distutils/apiref.html > > distutils.dir_util.create_tree > distutils.util.change_root > distutils.util.strtobool Unfortunate, as this has been my go-to function for this purpose for a long time.
  • Nishant
    Nishant about 2 years
    How about literal_eval?
  • Gunay Anach
    Gunay Anach about 2 years
    Like everything else in life, good things come to an end :(
  • MuhsinFatih
    MuhsinFatih about 2 years
    Part of me says capital letter "WARNING" is in order. On the other hand the other part says if someone is dumb enough to copy-paste the answer without thinking what it really does, they kinda deserved to be hacked
  • abhiyenta
    abhiyenta almost 2 years
    My big issue with the strtobool method is " Raises ValueError if val is anything else." You don't have to have to handling exceptions here. Just have it return false. While this answer is not wrong, there are other solutions that are better in my opinion, like the custom str2bool method that check for a list of values.
  • selle
    selle almost 2 years
    Be careful though, no validation are done that the return type is a boolean. json.loads("[42]".lower()) -> [42]
  • ShadowRanger
    ShadowRanger almost 2 years
    The definition of valid should be placed outside the function, or the dict will be rebuilt on every call, removing the majority of the performance benefit of using a dict in the first place.
  • AlexK
    AlexK over 1 year
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value.