views:

359

answers:

13

What is the best way to make a variable that works exactly like a bool but prints On or Off rather than True or False? Currently the program is printing: Color: True, whereas Color: On would make more sense.

For the record, I initially tried to make an OnOff class that inherits from bool:

class OnOff(bool):
    def __str__(self):
        if self: return 'On'
        else: return 'Off'

From the comments, I now understand that bool is a singleton, which is why this failed miserably:

Traceback (most recent call last):
    class OnOff(bool):
TypeError: Error when calling the metaclass bases
    type 'bool' is not an acceptable base type
+3  A: 
print "On" if color else "Off"    # Python 2.x
print ("On" if color else "Off")  # Python 3.x
Tim Pietzcker
The print statement is inside a class that loops over external variables, so this isn't very practical.
Josh
Shouldn't the bottom example work in both 2.x and 3.x?
Shane Reustle
+9  A: 
def Color(object):

    def __init__(self, color_value=False):
        self.color_value = color_value

    def __str__(self):
       if self.color_value:
          return 'On'
       else:
          return 'Off'

    def __cmp__(self, other):
        return self.color_value.__cmp__(other.color_value)

Although this could be overkill for you. :)

Rahul
This is the best solution so far, but that class won't work like a normal bool at all.
Josh
If you want to make it work like a normal bool override the <code>__eq__</code> method.
Rahul
Actually, the `__nonzero__` hook implements truth value testing.
The MYYN
Isn't it possible to inherit from `bool`?
Josh
That does not seem to be the right thing to do. Color has nothing to do with the <code>bool</code> type. Composition over inheritance for me as it gives greater control.
Rahul
Color *is* bool. I just want to change the print output (something that I thought would be quite easy).
Josh
If `Color` doesn't need to be a distinct type from `bool`, then this answer is overkill. @Josh, if I'm reading this right, you're concerned with *presentation*, not internal *representation* or *operation*. Internally, you want it to *be* a bool, right? If all you are concerned with is presentation, then you use a function other than `str()` to convert from `bool` to `str`. Like, say, `['Off','On'][my_bool_value]`.
Mike DeSimone
@Mike: That's not very practical for me, I've updated the first post explaining why.
Josh
A: 
mybool = {True: 'On', False: 'Off'}
mybool[True] == 'On'
mybool[False] == 'Off'
Rafael SDM Sierra
+4  A: 

My favorite trick is to use the bool to index an array:

return "Color: {0}".format(['Off','On'][has_color])

The caveat is that the value has to be False, True, 0, or 1. If you have something else, then you have to convert it to boolean first.

Mike DeSimone
Wouldn't a tuple `('Off','On')[has_color]` be more efficient?
Josh
@Josh: Honestly, I have no idea. The only guaranteed difference is that a list is mutable and a tuple is not, and here that doesn't matter. IIRC, the list is crested
Mike DeSimone
+7  A: 

print ("Off", "On")[value] works too (because (False, True) == (0,1))

THC4k
A: 

If you don't want to mess with print...

class BoolHack(object):
    def __init__(self):
        from sys import stdout
        self.realout = stdout

    def write(self, text):
        if text == 'False':
            text = 'Off'
        elif text == 'True':
            text = 'On'
        self.realout.write(text)

import sys

sys.stdout = BoolHack()

print "Hello world" # ==> Hello world
print 1             # ==> 1
print True, 10      # ==> On 10
print False         # ==> Off
print "True hack"   # ==> True hack

WARNING: Do not use in real production code! This is only for making your set of answers complete.

print calls str() on objects to print, and only then puts the string to stdout... so you cant check type of object. But it is quite rare to just print 'False' or 'True' as a single string, so in your very very specific case it might work.

liori
why would you give people such terrible ideas!
Winston Ewert
@Winston Ewert: even the crudest hack is sometimes useful.
liori
A: 

Bad trick, but not for Python 3:

True = "On"
False = "Off"
phimuemue
SyntaxError: assignment to keyword
jleedev
@jleedev: Forgot to mention it seems not to work with python3
phimuemue
A: 
class Color:
    def __init__(self,C):
    if C==True:
        self.col='On'
    else:
        self.col='Off'

    def __cmp__(self,other):
        return self.col 
Alexander Ivanov
+3  A: 

True and False are singletons. There is only one True and one False object in python. As a result attempting to inherit from them causes issues. (They just were not meant to be used in that way).

You cannot overload the logical and/or operations which will prevent you from creating a really bool-like object. It'll constantly revert back to python's bool.

So: Don't.

If you don't want your values to print as True and False, don't call print on them directly. Print is for quick and dirty output. If you want something more then it gives then you'll need to do more work. In this case, all you need is to ToOnOff function.

Winston Ewert
A: 

Pity you can't do True.__str__=lambda:"On"

Unfortunately it complains it is read-only. Anyway, that would be a VERY hackish way to do it!

neil
A: 

Try this curious one:

a = True
b = False
print a and 'On' or 'Off'
print b and 'On' or 'Off'
Paulo Scardine
+1  A: 

I am now using this solution based off Rahul's code:

class OnOff(object):
    def __init__(self, value):
        self._value = value

    def __str__(self):
       if self._value: return 'On'
       else: return 'Off'

    def __cmp__(self, other):
        return self._value.__cmp__(other)

I changed the __cmp__ function to enable the object to compare to bools and also changed some other minor stuff. Full credit to Rahul.

Josh
This is the code I used in the end. Despite this, I thought [Rahul's code](http://stackoverflow.com/questions/3687109#3687134) deserves the tick.
Josh
[Actually, I've changed my mind, I've found a way of doing this without creating a class.](http://stackoverflow.com/questions/3687109#3691891)
Josh
A: 

Taking the advice of the public, I've changed my mind and found a better way to solve my problem than by creating a class: Convert the menu items to strings outside the class. Allowing me to use the solution proposed by THC4k.

Unidiff:

         menu.items=((
             ('Play Game', True),
             '  ',
             'Speed: ', (speed, True),
             '  ',
             'Screen: ', (screen_width, True), 'x', (screen_height, True),
             '  ',
-            'Color: ', (color, True),
+            'Color: ', (("Off", "On")[color], True),
             '  ',
             ('Exit', True)
         ))

(I did the same for the other variables, I'm just trying to be succinct with the diff)

Josh