
Ron Adam <rrr@ronadam.com> wrote:
The dictionary fromkeys method seems out of place as well as miss-named. IMHO
It is perfectly named (IMNSHO ;), create a dictionary from the keys provided; dict.fromkeys() .
There are enough correct uses of it in the wild to keep the behavior, but it can be done in a better way.
I wasn't terribly convinced by your later arguments, so I'm -1.
I think this reads better and can be used in a wider variety of situations.
It could be useful for setting an existing dictionary to a default state.
# reset status of items. status.set_keys(status.keys(), v=0)
This can be done today: status.update((i, 0) for i in status.keys()) #or status.update(dict.fromkeys(status, 0))
Or more likely, resetting a partial sub set of the keys to some initial state.
The reason I started looking at this is I wanted to split a dictionary into smaller dictionaries and my first thought was that fromkeys would do that. But of course it doesn't.
Changing the bahvior of dict.fromkeys() is not going to happen. We can remove it, we can add a new method, but changing will lead to not so subtle breakage as people who were used to the old behavior try to use the updated method. Note that this isn't a matter of "it's ok to break in 3.0", because dict.fromkeys() is not seen as being a design mistake by any of the 'heavy hitters' in python-dev or python-3000 that I have heard (note that I am certainly not a 'heavy hitter').
What I wanted was to be able to specify the keys and get the values from the existing dictionary into the new dictionary without using a for loop to iterate over the keys.
d = dict(1='a', 2='b', 3='c', 4='d', 5='e')
d_odds = d.from_keys([1, 3, 5]) # new dict of items 1, 3, 5 d_evens = d.from_keys([2, 4]) # new dict of items 2, 4
There currently isn't a way to split a dictionary without iterating it's contents even if you know the keys you need before hand.
Um... def from_keys(d, iterator): return dict((i, d[i]) for i in iterator)
A del_keys method could replace the clear method. del_keys would be more useful as it could operate on a partial set of keys.
d.delkeys(d.keys()) # The current clear method behavior.
I can't remember ever needing something like this that wasn't handled by d.clear() .
Some potentially *very common* uses:
# This first one works now, but I included it for completeness. ;-)
mergedicts(d1, d2): """ Combine two dictionaries. """ dd = dict(d1) return dd.update(d2)
dict((i, d2.get(i, d1.get(i))) for i in itertools.chain(d1,d2))
splitdict(d, keys): """ Split dictionary d using keys. """ keys_rest = set(d.keys()) - set(keys) return d.from_keys(keys), d.from_keys(keys_rest)
I can't think of a simple one-liner for this one that wouldn't duplicate work.
split_from_dict(d, keys): """ Removes and returns a subdict of d with keys. """ dd = d.from_keys(keys) d.del_keys(keys) return dd
dict((i, d.pop(i, None)) for i in keys)
copy_items(d1, d2, keys): """ Copy items from dictionary d1 to d2. """ d2.update(d1.from_keys(keys)) # I really like this!
d2.update((i, d1[i]) for i in keys)
move_items(d1, d2, keys): """ Move items from dictionary d1 to d2. """ d2.update(d1.from_keys(keys)) d1.del_keys(keys)
d2.update((i, d1.pop(i, None)) for i in keys)
I think the set_keys, from_keys, and del_keys methods could add both performance and clarity benefits to python.
Performance, sometimes, for some use-cases. Clarity? Maybe. Your split* functions are a bit confusing to me, and I've never really needed any of the functions that you list.
So to summarize...
1. Replace existing fromkeys method with a set_keys method. 2. Add a partial copy items from_keys method. 3. Replace the clear method with a del_keys method.
Not all X line functions should be builtins. If you find that you are doing the above more often than you think you should, create a module with all of the related functionality that automatically patches the builtins on import and place it in the Python cheeseshop. If people find that the functionality helps them, then we should consider it for inclusion. As it stands, most of the methods you offer have a very simple one-line version that is already very efficient.
So this replaces two methods and adds one more. Overall I think the usefulness of these would be very good.
I don't find the current dictionary API to be lacking in any way other than "what do I really need to override to get functionality X", but that is a documentation issue more than anything.
I also think it will work very well with the python 3000 keys method returning an iterator. (And still be two fewer methods than we currently have.)
I'm sorry, but I can't really see how your changes would add to Python's flexibility without cluttering up interfaces and confusing current users. - Josiah