It's well-documented that Python's shelve module requires all keys to be strings and that there are various workarounds (see threads here and here). My question is, why does shelve require string keys? Given that I can pickle a dict that uses other objects as keys, and that shelve uses pickle under the hood, why can't shelve handle such keys itself? Do string keys make it vastly simpler to update only a piece of the persistent object rather than having to rewrite the whole thing (and if so, why)?
Because under the hood the shelve module uses one of bsddb, gdbm or dbm for storage, and they support only string keys.
You're right that you can pickle a dict that uses other objects as keys, but then when one key changes, you have to flush the whole storage. By using a key-value database like those, only the changed values are flushed.