Python Style Question

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu Oct 30 23:52:49 EDT 2014


Roy Smith wrote:

> In article <54521c8f$0$12982$c3e8da3$5496439d at news.astraweb.com>,
>  Steven D'Aprano <steve+comp.lang.python at pearwood.info> wrote:
> 
>> 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__)
> 
> Depending on how strictly you're trying to do input validation, the
> int(json.loads(obj)) may not be what you want.  It allows well-formed
> json encoding floats, for example.

Really?

py> int(json.loads(json.dumps(23.5)))
23

Damn! You're right.

Back to Plan A:

    elif isinstance(obj, str):
        try:
            return int(obj)
        except ValueError:
            if obj and obj.startswith('"') and obj.endswith('"'):
                return int(obj[1:-1])
            raise
    

But of course even the int() function itself may be a little more flexible
than we might want:

py> int('    1    ')
1


So I guess the lessons are:

* before writing code, you need to decide what the code is meant to do;

* and that includes what input must be rejected, not just what input 
  must be accepted.


> And, of course, since
> 
>>>> isinstance(True, int)
> True
> 
> this code accepts booleans.  Oh, but wait, that's by design :-)

Naturally :-)

If you wanted to avoid it, that's easy, add a clause:

    if isinstance(obj, bool):
        raise TypeError

at the start of the function.


-- 
Steven




More information about the Python-list mailing list