Question

I really hope this isn't a duplicate. I tried to search for my question and I couldn't seem to find it.

So I have a fairly simple function that converts feet to meters:

def feetToMeters(val):
    return numpy.array(val) * 0.3048

This works nicely and accepts ints, floats, arrays, and lists. However, if I put in a list (instead of a numpy array), I'd like to have a list returned. So I wrote this:

def feetToMeters(val):
    try:
        return val * 0.3084
    except TypeError:
        return [0.3084 * v for v in val]

(Alternatively I could use return list(numpy.array(val) * 0.3084) for the last line if I want to use numpy here, which I don't know if that really matters.)

Is this the best way to incorporate duck-typing here so that I can avoid the use of the type function? Originally I tried AttributeError, but it didn't work. Still, I am weary about TypeError even though it seems to work.

Would it be sacrilegious to use if type(val) is list instead?

Was it helpful?

Solution

Would it be sacrilegious to use if type(val) is list instead?

Yes, because it doesn't work for subclasses of list. If you want to go this way, at least do isinstance(val, list). Here's a solution that treats lists specially, and convert everything else (including scalars and tuples) to NumPy arrays:

def feetToMeters(feet):
    meters = np.asarray(feet) * 0.3048
    return list(meters) if isinstance(feet, list) else meters

Note that:

  • passing an instance of a subclass of list will cause a plain list to be returned;
  • passing a list of lists will cause a list of NumPy arrays to be returned.

You could extend this to handle more types specially, but in general, for each type to be handled, you need to write more code as you need to know how to construct that type. Therefore, this kind of type conversion is usually left to client code.

OTHER TIPS

Since you already use numpy I would avoid using exceptions here with something like

def feetToMeters(val):
    if numpy.isscalar(val):
        return val * 0.3084
    else:
        return numpy.array(val) * 0.3048

Catching TypeError is dangerous since it could be caused by many things besides a list. I would generally use isinstance(val, list) for this purpose.

The trick is that you are trying to support scalars and sequences - maybe something like this would work for you:

def feetToMeters(val):
    try:
        return type(val)(val * 0.3048)
    except TypeError:
        return type(val)(v*0.3048 for v in val)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top