Python Style Question

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu Oct 30 07:10:06 EDT 2014


Anton wrote:

> Let's say I have an incoming list of values *l*. Every element of *l* can
> be one of the following options: 
> 1) an integer value 
> 2) a string in form of '<int_value>', e.g. '7'
> 3) a string with a json serialization of an integer value, e.g. '"7"'
> 4) something else that should be ignored
> 
> I need to transform this list into another list with values from options
> 1)-3) coerced to int. The code below should do this.

I don't particularly like either version. I prefer this:

def load_int(obj):
    if isinstance(obj, int):
        # Case 1), an int, e.g. 7
        return obj
    elif isinstance(obj, str):
        # Case 2) and 3), a str or JSON serialised int.
        # E.g. '7' or '"7"'.
        try:
            return int(obj)
        except ValueError:
            return int(json.loads(obj))
    raise TypeError('require int or str, got %s' % type(obj).__name__)

load_int() covers the three cases you mention, and raises either ValueError
for malformed strings (e.g. 'x') or TypeError for things which aren't ints
(e.g. floats, dicts, etc.). Any other exception is probably a bug that
needs to be fixed.

Then, to cover case 4), ignoring everything else, you have a choice between
a procedural form:

values = []
for obj in l:
    try:
        values.append(load_int(obj))
    except (ValueError, TypeError):
        pass


or a functional form:

def tolerant_load_int(obj, default=None):
    try:
        return load_int(obj)
    except (ValueError, TypeError):
        return default

values = [n for n in map(tolerant_load_int, l) if n is not None]

# alternative to using map
values = [n for n in (tolerant_load_int(obj) for obj in l) if n is not None]



-- 
Steven




More information about the Python-list mailing list