[Python-Dev] Christmas Wishlist

Raymond Hettinger raymond.hettinger at verizon.net
Sun Dec 14 16:31:09 EST 2003

I. eval() to accept custom mapping arguments for globals and locals.
This makes it possible to write a smart __getitem__ method for
applications like spreadsheets or case-insensitive evaluation.

class LowerCaseDict(dict):
    def __getitem__(self, key):
        return dict.__getitem__(self, key.lower())

>>> print eval(raw_input('Okay kids, type in an expression:',

Okay kids, type in an expression:  HeX(20)

class SpreadSheet:
    _cells = {}
    def __setitem__(self, key, formula):
        self._cells[key] = formula
    def __getitem__(self, key):
        return eval(self._cells[key], self)

ss = SpreadSheet()
ss['a1'] = '5'
ss['a2'] = 'a1*5'

While this seems like a minor feature request, it presents amazing
opportunities to avoid writing lexers, parsers, interpreters by
transferring the work to the python interpreter.  Writing little
languages like the spreadsheet class becomes almost trivial.

II.  Timer.timeit to take an optional context argument.

>>> from timeit import Timer
>>> a = 20
>>> def f(x):
...     return x + 20

>>> Timer('f(10)', env=globals()).timeit()

The idea is to make it *much* easier to time functions or parts of
existing modules.  Having to write-out the definition in a long setup
string is cumbersome and interferes with syntax highlighting.  To
instrument modules with timeit, the timer setup string currently has to
re-import the whole module -- passing in an execution environment is
much more straight-forward.  And, as the example shows, passing in
globals() makes it easier to experiment with timings using the

III. enumerate to take an optional argument:
         enumerate([firstnumber=0,] iterable)

The idea is to make enumerate() a complete solution to the loop counter

for lineno, line in enumerate(1, file('hist.log')):
    print lineno, line

IV. list.sorted() to become just sorted().  All of the common use cases
read better without the "list." prefix:

>>> topscores = sorted(team.score for team in teams)[:10]
>>> for k, v in sorted(mydict.iteritems()):
       . . .
>>> byAge = operator.itemgetter('age')
>>> for age, students in groupby(sorted(studentbody, key=byAge),
...      print "Age group:", age
...      for student in students:
...           print '...', student.name, student.address

Also, this Christmas wish cures the weirdness that comes from the
classmethod approach:  

>>> [3,2,1].sorted('cbs')
['b', 'c', 's'].  

While I worry about the total number of builtins, opposing them on
principle is a recipe for putting tools where they don't belong.  IMO,
making list.sorted() a class method was a clumsy way of avoiding the
obvious solution and left it smelling a bit hackish.

Raymond Hettinger

More information about the Python-Dev mailing list