[Python-ideas] dict.fromkeys() better as dict().setkeys() ? (and other suggestions)

Ron Adam rrr at ronadam.com
Tue May 29 00:49:30 CEST 2007



The dictionary fromkeys method seems out of place as well as miss-named.  IMHO


In the current 2.5 branch it occurs only twice. (excluding tests)

----
$ grep -r "fromkeys" Lib/*.py
Lib/httplib.py:        header_names = dict.fromkeys([k.lower() for k in 
headers])
Lib/UserDict.py:    def fromkeys(cls, iterable, value=None):
----

In httplib.py, it is used as a set to remove duplicates.


There are enough correct uses of it in the wild to keep the behavior, but 
it can be done in a better way.

I feel it really should be called set_keys and implemented as a method that 
operates on the current dictionary instead of being a constructor for a new 
dictionary.  That will allow you to add keys with a default value to an 
already existing dictionary, or to create a new one with a dictionary 
constructor.

      dict().set_keys(s, v=None)    # The current fromkeys behavior.

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)

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.

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.

A from_keys method would be the inverse complement of the update method.


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.


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)

      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)

      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

      copy_items(d1, d2, keys):
          """ Copy items from dictionary d1 to d2. """
          d2.update(d1.from_keys(keys))      # I really like this!

      move_items(d1, d2, keys):
          """ Move items from dictionary d1 to d2. """
          d2.update(d1.from_keys(keys))
          d1.del_keys(keys)


I think the set_keys, from_keys, and del_keys methods could add both 
performance and clarity benefits to python.

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.


So this replaces two methods and adds one more.  Overall I think the 
usefulness of these would be very good.

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.)

Any thoughts?

Cheers,
   Ron



More information about the Python-ideas mailing list