What is the canonical way to handle various types in Python?

I have a function where I need to generate different output lines for another program that I call, depending on what type it wants.

Basically, the called program needs a command line argument indicating what type it was called with.

Fortunately, I found this answer on SO on how to check a type variable. But I noticed how people also objected that type checking produces a "non-object oriented" design. So, is there another way, supposedly a more “more object oriented” way of handling this without explicit type checking?

The code I have now looks 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 fine, but I just wanted to find out if there is any technique that I don’t know about.

+6
python oop paradigms
source share
4 answers

I don’t think that Double Dispatching or Multimethods are particularly relevant and have little to do with the objections that people have experienced to this other SO answer.

It is not surprising that in order to do what you do more object-oriented, you need to introduce some objects (and corresponding classes) into it. When you create each value, an instance of the class would allow - in fact, practically power - you stopped checking its type. The changes in your code example below show a very simple way that this could be 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 for indirect access to its attributes, but just doing the above eliminates the infamous type checking. A more object-oriented design is likely to have a separate subclass for each type of Value , for which everyone uses a common set of methods for clients, for example myfunc() , to create, process and extract information from them.

Another advantage of using objects is that you do not need to modify myfunc() if / when you add support for the new "Value" type to your application, if your abstraction of the "Value" entity is good, that is.

+3
source share

You can use Double Dispatch or Multimethods .

+5
source share
  But I noticed how people also raised objections, that checking for types betrays a "not object oriented" design 

This is actually called the duck print style ("If it looks like a duck and quacks, like a duck, it must be a duck"). And it is a python language that recommends using this programming style.

and with a duck set, call EAFP (it's 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 looks 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 magic program (I don’t know if this is your script or ...), and therefore in all cases your program will receive a string, so just try to convert it to 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 all your code is, but you can follow the example above, it is more pythonic, and remember that each rule has its own exception, so maybe your case is an exception and you better check the type.

Hope this helps you figure it out.

+3
source share

This has more to do with the technical question in the big question than with the design of one small function. There are many different ways to do this, but they more or less break down to the same process of general thought. Back where val is known, it should indicate how it should be translated into the arg command line. If it were me, I would probably make val a class that had a command line function that did the right thing. You can also assign a myfunc type function to a variable, and then call it when you need to.

edit: To clarify the latest version of something in the lines

 Val = "a string" myfunc = myfuncStringVersion 

more or less do the same as with val packaging in a class, only broken down into value and function, since you may not want to wrap val in a class.

+1
source share

All Articles