# New user's initial thoughts / criticisms of Python

Joshua Landau joshua at landau.ws
Mon Nov 11 21:50:35 CET 2013

```On 11 November 2013 10:39, Chris Angelico <rosuav at gmail.com> wrote:
> On Mon, Nov 11, 2013 at 9:09 PM,  <lorenzo.gatti at gmail.com> wrote:
>> Regarding the "select" statement, I think the most "Pythonic" approach is using dictionaries rather than nested ifs.
>> Supposing we want to decode abbreviated day names ("mon") to full names ("Monday"):
>
> You can't [normally], for instance, build up a
> dictionary that handles inequalities, but you can do that with elif.
> [...] Consider the following logic:
>
> A 'minor weapon' is based on a roll of a 100-sided dice. If it's 01 to
> 70, "+1 weapon: 2,000gp [weapon]"; if it's 71 to 85, "+2 weapon:
> 8,000gp [weapon]"; if 86 to 90, "Specific weapon [minor specific
> weapon]"; and if 91 to 100, "Special ability [minor special weapon]
> and roll again".
>
> My code to handle that starts out with this array:
>
> "minor weapon":({
>     70,"+1 weapon: 2,000gp [weapon]",
>     85,"+2 weapon: 8,000gp [weapon]",
>     90,"Specific weapon [minor specific weapon]",
>     100,"Special ability [minor special weapon] and roll again",
> }),
>
> (that's Pike; in Python it'd be a list, or maybe a tuple of tuples),
> and denormalizes it into a lookup table by creating 70 entries quoting
> the first string, 15 quoting the second, 5, and 10, respectively. So,
> with a bit of preprocessing, a lookup table (which in this case is an
> array (list), but could just as easily be a dict) can be used to
> handle inequalities.

The obvious way to me is a binary search:

from bisect import bisect_left

class FloorMap:
def __init__(self, dct):
self.indexes = sorted(list(dct))
self.dct = dct

def __getitem__(self, itm):
index = self.indexes[bisect_left(self.indexes, itm)]
return self.dct[index]

minor_weapon = FloorMap({
70:  "+1 weapon: 2,000gp [weapon]",
85:  "+2 weapon: 8,000gp [weapon]",
90:  "Specific weapon [minor specific weapon]",
100: "Special ability [minor special weapon] and roll again"
})

minor_weapon[63]
#>>> '+1 weapon: 2,000gp [weapon]'

The precise details of the wrapper class here are just to make
initialisation pretty; it could be done straight from a pair of lists
too:

from bisect import bisect_left

minor_weapon_indexes = 70, 85, 90, 100
minor_weapon_descriptions = (
"+1 weapon: 2,000gp [weapon]",
"+2 weapon: 8,000gp [weapon]",
"Specific weapon [minor specific weapon]",
"Special ability [minor special weapon] and roll again"
)

minor_weapon_descriptions[bisect_left(minor_weapon_indexes, 80)]
#>>> '+2 weapon: 8,000gp [weapon]'

Compare to

if 80 <= 70:
res = "+1 weapon: 2,000gp [weapon]"

elif 80 <= 85:
res = "+2 weapon: 8,000gp [weapon]"

elif 80 <= 90:
res = "Specific weapon [minor specific weapon]"

elif 80 <= 100:
res = "Special ability [minor special weapon] and roll again"

which although shorter¹ is a lot less data-driven and much less reusable.

¹ Longer if you ignore the import and class declaration.

```