pythonic way of composing itemgetter and attrgetter?

Question:

I’ve got some code I’m porting to Cython which had a line like

my_list.sort(key=lambda x: x.attr[item])

Is there a nice pythonic way of avoiding the closure with some combination of itemgetter and attrgetter?

Asked By: gmoss

||

Answers:

The key is to use the package functional:

from functional import compose
from operator import attrgetter, itemgetter
my_list.sort(key=compose(itemgetter(item), attrgetter('attr')))
Answered By: gmoss

The accepted self answer feels like a mistake/de-optimization to me.

My guess is that the unstated problem is that closures aren’t supported inside cpdef functions. However closures are supported inside both cdef and def functions.

My view is that there’s rarely a reason to use cpdef functions – they have all the disadvantages of def functions and all the disadvantages of cdef functions (plus a few more unique disadvantages, like no closures) so I usually treat them as the worst of all worlds. Ideally you’d just decide if something should be a Cython/C interface (cdef) or a Python interface def and use that. Also remember that the type of function makes little to no difference to how the code inside it is compiled, so a find/replace of def for cpdef really is redundant when porting to Cython.

Therefore for this case I would keep the closure as written in the original Python code and pick one of:

  1. Just keep it as a def function.
  2. If you really need to call it from both Python and need the speed of a cdef call when calling it from Cython then write a cdef function and a really small def function wrapper for the cdef function.

The code in the accepted answer is de-optimizing an attribute lookup and an index into at least(?) 3 Python function calls, an attribute lookup, and an index.

Answered By: DavidW
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.