[Python-ideas] Optional kwarg making attrgetter & itemgetter always return a tuple
Steven D'Aprano
steve at pearwood.info
Fri Sep 14 03:20:38 CEST 2012
On 13/09/12 23:15, Masklinn wrote:
> attrgetter and itemgetter are both very useful functions, but both have
> a significant pitfall if the arguments passed in are validated but not
> controlled: if receiving the arguments (list of attributes, keys or
> indexes) from an external source and *-applying it, if the external
> source passes a sequence of one element both functions will in turn
> return an element rather than a singleton (1-element tuple).
For those who, like me, had to read this three or four times to work out
what Masklinn is talking about, I think he is referring to the fact that
attrgetter and itemgetter both return a single element if passed a single
index, otherwise they return a tuple of results.
If a call itemgetter(*args)(some_list) returns a tuple, was that tuple
a single element (and args contained a single index) or was the tuple
a collection of individual elements (and args contained multiple
indexes)?
py> itemgetter(*[1])(['a', ('b', 'c'), 'd'])
('b', 'c')
py> itemgetter(*[1, 2])(['a', 'b', 'c', 'd'])
('b', 'c')
> This means such code, for instance code "slicing" a matrix of some sort
> to get only some columns and getting the slicing information from its
> caller (in situation where extracting a single column may be perfectly
> sensible) will have to implement a manual dispatch between a "manual"
> getitem (or getattr) and an itemgetter (resp. attrgetter) call, e.g.
>
> slicer = (operator.itemgetter(*indices) if len(indices)> 1
> else lambda ar: [ar[indices[0]])
Why is this a problem? If you don't like writing this out in place, write
it once in a helper function. Not every short code snippet needs to be in
the standard library.
> This makes for more verbose and less straightforward code, I think it
> would be useful to such situations if attrgetter and itemgetter could be
> forced into always returning a tuple by way of an optional argument:
-1
There is no need to add extra complexity to itemgetter and attrgetter for
something best solved in your code. Write a helper:
def slicer(*indexes):
getter = itemgetter(*indexes)
if len(indexes) == 1:
return lambda seq: (getter(seq), ) # Wrap in a tuple.
return getter
--
Steven
More information about the Python-ideas
mailing list