New user's initial thoughts / criticisms of Python
Joshua Landau
joshua at landau.ws
Mon Nov 11 15:50:35 EST 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.
More information about the Python-list
mailing list