views:

69

answers:

2

Hi,

Relatively new to python. I recently posted a question in regards to validating that a data type is boolean. [http://stackoverflow.com/questions/1708349/use-a-single-decorator-for-multiple-attributes%5D%5B1%5D

The answers given referenced duck typing. I have a simple example, and want to make sure I understand. If my code is:

class Foo4(object):
    def __init__(self):
        self.bool1=True

    def send_rocket(self, bool_value):
        if not bool_value:
            print "Send rocket ship to sun first... bad move."
         print "Send rocket ship to Mars... good move."

f=Foo4()
f.send_rocket(f.bool1) 
#Send rocket ship to Mars... good move.

f.bool1=None
f.send_rocket(f.bool1) 
#Send rocket ship to sun first... bad move.
#Send rocket ship to Mars... good move.

If I understand duck typing somewhat correctly, in the above class I trust that bool1 will always be a boolean value: I should not be checking whether bool1 == False or bool1 == True. When someone uses my module incorrectly, ie, bool1 = None, the method exectues something I would not have wanted performed without indication there was a problem... and the people in the rocketship die.

Another way I could have written the code to ensure bool1 is always a true boolean would be (credits for BooleanDescriptor in link above!):

class BooleanDescriptor(object):
    def __init__(self, attr):
        self.attr = attr

    def __get__(self, instance, owner):
        return getattr(instance, self.attr)

    def __set__(self, instance, value):
        if value in (True, False):
            return setattr(instance, self.attr, value)
        else:
            raise TypeError

class Foo4(object):
    def __init__(self):
        self._bool1=True
    bool1 = BooleanDescriptor('_bool1')

    def send_rocket(self, bool_value):
        if not bool_value:
            print "Send rocket ship to sun... bad move."
        print "Send rocket ship to Mars... good move."

f=Foo4()
f.send_rocket(f.bool1)
#Send rocket ship to Mars... good move.

f.bool1=None
#TypeError.
#Never gets here: f.send_rocket(f.bool1)

Do I understand the first way to go (not checking) is the correct way to go? I mean, I could always have written the code explicitly in the first example as:

    if bool_value ==True:
        print "do something"
    elif bool_value == False:
        print "do something else"
    else:
        print "invalid boolean value"

But if I do that in every method et cetera where I use bool1, why in the heck would I just not have validate that bool1 was a true boolean value in the first place (DRY!)!?!? :-)

Thanks!

Paul

A: 

I'd expect that wrapping a dynamically typed value with a class that forces it to be, essentially, statically typed is not the way to go.

I'm not an expert, but I expect that your final method is the best one (i.e. check for true, false, or else).

Oren Mazor
+2  A: 

The usual Python style is the first approach.

For example, I may want to use your library with something that cannot decide whether to go to the sun or to mars until the very last moment. So I might pass in an instance of this class:

class LastMinuteDecision(object):

    def __bool__(self):
        return make_decision_now()

If you had stuck some tests in there, thinking you knew better than me how I was going to call your library, then I couldn't do that, and I would be very annoyed and probably tell you to stop writing Java (or whatever) in Python...

[edit: in case it's not clear, the __bool__ method makes the instance "look like" a boolean. It is called when the language expects a boolean value.]

You might think it crazy, but it works surprisingly well.

andrew cooke