views:

530

answers:

7

False is equivalent to 0 and True is equivalent 1 so it's possible to do something like this:

def bool_to_str(value):
    """value should be a bool"""
    return ['No', 'Yes'][value]

bool_to_str(True)

Notice how value is bool but is used as an int.

Is this this kind of use Pythonic or should it be avoided?

+14  A: 

surely:

def bool_to_str(value):
    """value should be a bool"""
    return 'Yes' if value else 'No'

is more readable.

SilentGhost
I would argue with that one... yes, using the `x if foo else y` thingy is more pythonic, but I still think that it just looks ugly and often bloats code. I think the code in the question **looks** clearer, it may be confusing for people who don't know about the implicit bool to int conversion, but `x if foo else y` is just as confusing for someone that comes from the `foo ? x : y` world of things. Even though I have to admit, that for people which are learning their first language, the `x if foo else y` may be the clearest one.
Ivo Wetzel
@Ivo, +1 as I agree on the substance, but I disagree that the "ternary" construct (with the condition in the middle, not at the start like in C) is particularly natural or clear to newbies (it's the least of evils in many cases -- that's a different thing;-).
Alex Martelli
why the downvote?
SilentGhost
@Silent, not sure, looks like I got one, too, at about the same time (and also w/o comments!).
Alex Martelli
+1  A: 

At the very least, use a dict for forward compatibility.

return {False: 'No', True: 'Yes'}[value]

But don't do it this way. Use a full if statement instead.

if value:
  return 'Yes'
return 'No'
Ignacio Vazquez-Abrams
Why 'for forward compatibility'? This behaviour is guaranteed by the Python reference manual; there's no reason to expect it to change in the forseeable future.
Mark Dickinson
+2  A: 

It is actually a feature of the language that False == 0 and True == 1 (it does not depend on the implementation): http://stackoverflow.com/questions/2764017/is-false-0-and-true-1-in-python-an-implementation-detail-or-guaranteed-by-t

However, I do agree with most of the other answers: there are very readable ways of obtaining the same result as ['No', 'Yes'][value], through the use of the … if value else … or of a dictionary, which have the respective advantages of hinting and stating that value is a boolean.

Plus, the … if value else … follows the usual convention that non-0 is True: it also works even when value is True but with value == -2, as hinted by dahlia. The list and dict approaches are not as robust, in this case.

EOL
+40  A: 

I'll be the odd voice out (since all answers are decrying the use of the fact that False == 0 and True == 1, as the language guarantees) as I claim that the use of this fact to simplify your code is perfectly fine.

Historically, logical true/false operations tended to simpy use 0 for false and 1 for true; in the course of Python 2.2's life-cycle, Guido noticed that too many modules started with assignments such as false = 0; true = 1 and this produced boilerplate and useless variation (the latter because the capitalization of true and false was all over the place -- some used all-caps, some all-lowercase, some cap-initial) and so introduced the bool subclass of int and its True and False constant.

There was quite some pushback at the time since many of us feared that the new type and constants would be used by Python newbies to restrict the language's abilities, but Guido was adamant that we were just being pessimistic: nobody would ever understand Python so badly, for example, as to avoid the perfectly natural use of False and True as list indices, or in a summation, or other such perfectly clear and useful idioms.

The answers to this thread prove we were right: as we feared, a total misunderstanding of the roles of this type and constants has emerged, and people are avoiding, and, worse!, urging others to avoid, perfectly natural Python constructs in favor of useless gyrations.

Fighting against the tide of such misunderstanding, I urge everybody to use Python as Python, not trying to force it into the mold of other languages whose functionality and preferred style are quite different. In Python, True and False are 99.9% like 1 and 0, differing exclusively in their str(...) (and thereby repr(...)) form -- for every other operation except stringification, just feel free to use them without contortions. That goes for indexing, arithmetic, bit operations, etc, etc, etc.

Alex Martelli
+1 for the history lesson :)
the_void
+1 I learned something today
MAK
+1 Contrast with Ruby, which forces `val?1:0` and similar gymnastic junk if you need to treat a bool as an int.
gnibbler
"nobody would ever understand Python so badly, for example, as to avoid the perfectly natural use of False and True as list indices". I'm certainly not opposed to using them that way, but I in no way think it's "natural" for people to index into a list with a boolean type, unless they happen to know that `bool` subclasses `int`
Michael Mrozek
Interesting history lesson indeed! However, I would argue that there is something telling in the fact that most people distinguish between booleans and integers (I do…). In a way, people are defining what it means to "use Python as Python": most of us do feel that there is a logical distinction between the two types (mathematics mostly do too: logic does not need arithmetic). I'm quite happy with the fact that Python allows us to think this way.
EOL
As dahlia's answer shows, the index approach is unnecessarily restrictive (compared to the `… if … else …` approach).
EOL
A: 

Unlike C/C++, In Python False and True are not 0 and 1. True and False are separate symbols in the symbol table.

None, emtpy lists, empty dicts, zero length strings and 0 evaluate to False, everything else is True. Take a look at this:

tests = [-1,0,1,-2,None,'',[], [[]], {},'Hello']

def test(inp):
   if inp:
       print "%s evaluates to True" % str(inp)
   else:
       print "%s evaluates to False" % str(inp)

[ test(i) for i in tests]

The correct to achieve what you desire is to evaluate the input and decide the response. e.g.:

def bool_to_str(value):
     return "Yes" if value else "No"
sharjeel
Class `bool` subclasses `int`. `isinstance(True, int) == True == 1`
kwatford
+3  A: 

Your code seems inaccurate in some cases:

>>> def bool_to_str(value):
...     """value should be a bool"""
...     return ['No', 'Yes'][value]
...
>>> bool_to_str(-2)
'No'

And I recommend you to use just the conditional operator for readability:

def bool_to_str(value):
    """value should be a bool"""
    return "Yes" if value else "No"
dahlia
The function's name is `bool_to_str`, with doc comment `value should be a bool`, and you're surprised that it gives a wrong answer when you pass it `-2` :)
Michael Mrozek
On the other hand, I would argue that it is usual to assume that non-0 means True… What dahlia's example shows is that the `… if … else …` method allows you to produce code that is not unnecessarily restrictive.
EOL
+1 While I agree with Alex Martelli's answer in general, in this case it seems "more Pythonic" to take advantage of the implicit conversion to `bool` afforded by `... if ... else ...`. Then the function works for bools and anything else. Though perhaps just not the best example, as I don't disagree with the idea of using bools as ints.
shambulator
A: 

Using a bool as an int is quite OK because bool is s subclass of int.

>>> isinstance(True, int)
True
>>> isinstance(False, int)
True

About your code: Putting it in a one-line function like that is over the top. Readers need to find your function source or docs and read it (the name of the function doesn't tell you much). This interrupts the flow. Just put it inline and don't use a list (built at run time), use a tuple (built at compile time if the values are constants). Example:

print foo, bar, num_things, ("OK", "Too many!)[num_things > max_things]
John Machin