[Tutor] FW: value range checker

Albert-Jan Roskam sjeik_appie at hotmail.com
Fri Aug 28 17:53:00 CEST 2015


(sorry, Peter, Alan, I sent two mails to you privately. I just switched from Yahoo to Hotmail for DMARC reasons. Still getting used to Hotmail.)



> Subject: RE: [Tutor] value range checker
> Date: Fri, 28 Aug 2015 10:14:49 +0000
>
> ----------------------------------------
>> To: tutor at python.org
>> From: __peter__ at web.de
>> Date: Thu, 27 Aug 2015 09:48:46 +0200
>> Subject: Re: [Tutor] value range checker
>>
>> Albert-Jan Roskam wrote:
>>
>>> I have a written a function checks the validity of values. The ranges of
>>> valid values are stored in a database table.
>>>
>>> Such a table contains three columns: category, min and max. One record of
>>> such a table specifies the range for
>>>
>>> a certain category, but a category may be spread out over multiple
>>> records.
>>
>>> My questions:
>>
>>> def get_valid_value_lookup(records):
>>> """
>>> Translates value range information (from a database table)
>>> into a dictionary of the form {<category>: [<range of accepted
>>> values>]} """
>>> Boundaries = collections.namedtuple("Boundaries", "category min max")
>>> records = [Boundaries(*record) for record in records]
>>> boundaries = collections.defaultdict(list)
>>> crap = [boundaries[record.category].__iadd__(range(record.min,
>>> record.max + 1))
>>> for record in records]
>>> return dict(boundaries)
>>
>>
>>> [1] @ is_valid: is there a better way to do this? I mostly don't like the
>>> [use of the __iadd__ dunder method.
>>
>> When you find yourself using a list comprehension for its side effect it is
>> high time to switch to a for loop. So
>>
>> def get_valid_value_lookup(records):
>> boundaries = {}
>> for category, minval, maxval in records:
>> boundaries.setdefault(category, []).extend(range(minval, maxval+1))
>> return boundaries
>
>
> ah, this indeed looks better. Thank you!
>
>
>>> [2] @ is_valid2: Perhaps an answer to my previous question. Is this a
>>> [better approach?
>>
>> As long as the size of the ranges is manageable and you are not actually
>> seeing float values I'd stick with the dead simple first version.
>
>
> The acronym "YAGNI" came to mind when I wrote that function. :-) But I was just curious how it could be generalized an this was a first attempt.
>
>
>> Replace the list in get_valid_value_lookup() with a set
>>
>> boundaries.setdefault(category, set()).update(range(minval, maxval+1))
>>
>> and you get O(1) lookup for free.
>>
>>> def is_valid2(lookup, category, value):
>>> """Return True if value is member of a list of a given category, False
>>> otherwise."""
>>> # this version also knows how to deal with floats.
>>>
>>> try:
>>>
>>> L = lookup[category]
>>> except KeyError:
>>> raise KeyError("Invalid category: %r" % category)
>>>
>>> adjusted_value = value if int(value) in (L[0], 0, L[-1]) else
>>> math.ceil(value)
>>> try:
>>> chopfunc = bisect.bisect_right if value < L[0] else
>>> bisect.bisect_left return L[chopfunc(L, value)] == adjusted_value
>>> except IndexError:
>>> return False
>>
>> I don't understand what this is supposed to do:
>>
>> (1) for bisect to work correctly the list has to be sorted. Your
>> get_valid_value_lookup() doesn't do that
>
>
> awww, good point. The rows are currently sorted in the database, but it is still a simple "just in case" thing to to sort the data.
>
>
>> (2) Why/how are L[0], 0, and L[-1] special?
>
>
> No idea actually. You've spotted the bug I *deliberately* added? :-))
>
>
>> (3) Given a sorted list L there should be no need to bisect_whatever for
>> value < L[0]
>>
>>
>>> [3] I am inheriting a this system. It feels a bit strange that these range
>>> [check values are stored in a database.
>>>
>>> Would yaml be a better choice? Some of the tables are close to 200
>>> records.
>>
>> Unless you're encountering an actual inconvenience just keep it like it is.
>> Yea, I'm a lazy bastard ;)
>
>
> :-) I would like to store the validation and check functions in a central location where they can easily be (re)used and maintained.
>
> For example, we also have to do a modulus-11 check, and I really am relucatant to have multiple functions for the same check (e.g.
>
> one an SQL check constraint, one in Python, perhaps even one in JavaScript.
>
>
> 		 	   		  


More information about the Tutor mailing list