views:

182

answers:

4

I have a function where I need to generate different output strings for another program I invoke, depending on which type it wants.

Basically, the called program needs a command line argument telling it which type it was called with.

Happily I found this answer on SO on how to check a variable for type. But I noticed how people also raised objections, that checking for types betrays a "not object oriented" design. So, is there some other way, presumable more "more object oriented" way of handling this without explicitly checking for type?

The code I have now goes something like this:

def myfunc(val):
    cmd_type = 'i'
    if instance(val, str):
        cmd_type = 's'

    cmdline = 'magicprogram ' + cmd_type + ' ' + val
    Popen(cmdline, ... blah blah)
    ...

which works just fine, but I just wanted to know if there is some technique I am unaware of.

+4  A: 

You could use Double Dispatch or Multimethods.

pillmuncher
And in Python, that would be http://www.artima.com/weblogs/viewpost.jsp?thread=101605 and http://en.wikipedia.org/wiki/Multiple_dispatch#Python I assume. Thanks!
Amigable Clark Kant
For my purposes, I think I will stick to checking the type, but this was a very enlightening experience, both for how Python works and how people think about these issues. Accepting your answer since it most closely answers my question as it was formulated.
Amigable Clark Kant
+1  A: 

This is more of an engineering in the large question than how to design one small function. There are many different ways to go about it, but they more or less break down to the same general thought process. Back where the type of val is known it should specify how it should be translated into a command line arg. If it were me I would probably make val be a class that had a To Command Line function that did the right thing. You could also assign a type specific myfunc function to a variable then call that when you need to.

edit: To explain the last version something along the lines of

Val = "a string"
myfunc = myfuncStringVersion

more or less doing the same thing you would with wrapping val in a class only broken out into a value and function since you might not want to wrap val in a class.

stonemetal
"You could also assign a type specific myval function to a variable then call that when you need to." <---- I read it over and over again, I don't get it.
Amigable Clark Kant
@Amigable Clark Kant Sorry about that hopefully it makes more sense now.
stonemetal
+3  A: 
    But I noticed how people also raised objections, 
that checking for types betrays a "not object oriented" design

Actually it's called Duck typing style ("If it looks like a duck and quacks like a duck, it must be a duck."), and it's the python language that recommend using this still of programming .

and with duck typing come something call EAFP (Easier to Ask Forgiveness than Permission)

    presumable more "more object oriented" way of handling this without 
   explicitly checking for type?

you mean more pythonic, basically what will be more pythonic in your case is something like this:

def myfunc(val):
    cmd_type = 'i'

    # forget about passing type to your magicprogram
    cmdline = 'magicprogram  %s ' % val 
    Popen(cmdline, ... blah blah)

and in your magicprogramm (i don't know if it's your script or ...), and because in all cases your program will get a string so just try to convert it to whatever your script accept;

from optparse import OptionParser

# ....

if __name__ == '__main__':

    parser = OptionParser(usage="blah blah")

    # ...
    (options, args) = parser.parse_args()

    # Here you apply the EAFP with all type accepted.
    try:
        # call the function that will deal with if arg is string
        # remember duck typing.
    except ... :
        # You can continue here

I don't know what's all your code, but you can follow the example above it's more pythonic, and remember every rule has their exception so maybe your case is an exception and you will better be with type checking.

hope this will clear things for you

singularity
Ok, in my case magicprogram is NET-SNMP, and changing it is not an option. But thanks for the thoughts anyways.
Amigable Clark Kant
Ahh ok, but i hope that my answer have clear things about python philosophy ; Duck typing and EAFP :)
singularity
"it's has something to do Duck typing style, and it's python philosophy and not object oriented" isn't true and doesn't require Duct Typing. It's true for any language which supports [polymorphism](http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming) and many (most?) OO ones do, I believe.
martineau
@martineau: yes, i can see your confusion maybe i didn't make this sentence clear enough i will edited
singularity
@singularity: Your answer is now clearer. Perhaps it is I who wasn't. What I meant to point out was that while using duck typing + EAFP together is definitely Pythonic and is possible because it dynamically typed language, using it in your answer however does not make things object-oriented. That's fine, but the OP specifically asked for something object-oriented that eliminated type checking, not for something more Pythonic. Fortunately Python is also supports object-oriented programming, which is what I attempted to demonstrate in my answer. Polymorphism could have been used, but I didn't.
martineau
+2  A: 

I don't think Double Dispatching or Multimethods are particularly relevant nor have much to do with the objections people had to that other SO answer.

Not surprisingly, to make what you're doing more object-oriented, you'd need introduce some objects (and corresponding classes) into it. Making each value an instance of a class would allow -- in fact, virtually force -- you to stop checking its type. The modifications to your sample code below show a very simple way this could have been done:

class Value(object):
    """ Generic container of values. """
    def __init__(self, type_, val):
        self.type = type_   # using 'type_' to avoid hiding built-in
        self.val = val

def myfunc(val):
    # Look ma, no type-checking!
    cmdline = 'magicprogram {obj.type} {obj.val}'.format(obj=val)
    print 'Popen({!r}, ... blah blah)'.format(cmdline)
    # ...

val1 = Value('i', 42)
val2 = Value('s', 'foobar')

myfunc(val1)  # Popen('magicprogram i 42', ... blah blah)
myfunc(val2)  # Popen('magicprogram s foobar', ... blah blah)

It would be even more object-oriented if there were methods in the Value class to access its attributes indirectly, but just doing the above gets rid of the infamous type-checking. A more object-oriented design would probably have a different subclass for each kind of Value which all share a common set of methods for clients, like myfunc(), to use to create, manipulate, and extract information from them.

Another benefit of using objects is that you shouldn't have to modify myfunc() if/when you add support for a new type of 'Value` to your application -- if your abstraction of the essence of a "Value" is a good one, that is.

martineau