Finding the type of indexing supported by an object?
Alex Martelli
aleax at mac.com
Wed Aug 23 10:40:19 EDT 2006
Derek Peschel <dpeschel at eskimo.com> wrote:
> Here are two functions.
>
> def invert_dict_to_lists(dict):
> lists = {}
> for key in dict:
> value = dict[key]
> if not value in lists:
> lists[value] = [key]
> else:
> lists[value].append(key)
> return lists
>
> def invert_list_to_lists(list):
> lists = {}
> for key in range(len(list)):
> value = list[key]
> if not value in lists:
> lists[value] = [key]
> else:
> lists[value].append(key)
> return lists
>
> They are the same except for the expression in "for key in ...". Can they
> be combined into one function? How can I determine if the argument is
They can easily be refactored, if that's what you mean:
def _invert_internal(container, keys):
lists = {}
for key in keys:
value = container[key]
if not value in lists:
lists[value] = [key]
else:
lists[value].append(key)
return lists
def invert_dict_to_lists(adict):
return _invert_internals(adict, adict)
def invert_list_to_lists(alist):
return _invert_internals(alist, xrange(len(alist)))
I've also performed a few other minor enhancements (never name things
dict or list because that hides the builtin types, use xrange vs range).
I have not changed the 4 lines in the if/else though I don't like them
(if not.../else is a very confusing construct -- at a minimum I'd
rephrase it as if/else swapping the bodies of the two clauses).
If you want to add a generic form accepting either lists or dicts you
need a try/except statement inside it, e.g.:
def invert_generic(container):
try:
container['zap']
except TypeError:
keys = xrange(len(container))
except KeyError:
keys = container
else:
keys = container
return _invert_internal(container, keys)
Of course there are all sort of fragilities here -- e.g., something like
invert_dict_to_lists({23:[45]}) will crash and burn. But that's quite
separate from the issue of distinguishing a dict from a list, which is
what the generic function is doing, showing how to handle exceptions for
the purpose. Of course, there's no way to use a "totally" generic
container, because there are no real limits to the keys it may accept
(including infinite sets thereof, computing values in __getitem__).
Alex
More information about the Python-list
mailing list