views:

47

answers:

2

I have the following code:

def f(cls, value):
  # cls is a class
  # value is a string value
  if cls == str:
    pass # value is already the right type
  elif cls == int:
    value = int(value)
  elif cls == C1:
    value = C1(value)
  elif cls == C2:
    value = C2(value)
  elif cls == C3
    # in this case, we convert the string into a list of objects of class C3
    value = C3.parse(value)
  else
    raise UnknownClass(repr(cls))
  return value

Obviously, I'm trying to replace it with something like:

def f(cls, value)
   return cls(value)

Unfortunately, in some cases (if cls == C3), the parsing of the input results in a list of objects of that class, rather than just one object. What's a neat way to handle this? I have access to all the classes.

A: 

That depends on what you'd do with the list. This is the simplest way:

obj = cls(value)

if type(obj) == list:

handle_list(obj)

return obj

Hoa Long Tam
its good practice to use isinstance built-in method instead of using type !
Tumbleweed
+2  A: 

If most cases are best handled by calling cls, and a few are best handled otherwise, simplest is to single out the latter:

themap = {C3: C3.parse}
for C in (str, C1, C2):
    themap[C] = C

def f(cls, value):
    wot = themap.get(cls)
    if wot is None:
        raise UnknownClass(repr(cls))
    return wot(value)

Note that calling str on a string is a pretty fast noop, so it's generally worth avoiding the "singling out" of that specific case in favor of code simplicity.

Alex Martelli
There's no way to return a list of X instead of just X from X(), I assume?
max
@max, when you write a `class X`, you _can_ override `X.__new__` to return whatever you want (if not an `X` instance, `X.__init__` isn't called on it) -- of course this can have serious drawbacks, making it hard for example to have a single `X` instance (so how are you getting the instances to put in that list...?) - not impossible, but extremely inconvenient. `classmethod` is usually a better way to frame "alternate" constructors.
Alex Martelli