Problem with shelve / nested lists

Alex Martelli aleax at aleax.it
Sun Jul 14 04:08:23 EDT 2002


Michael Schmitt wrote:

> Hello.
> I'm trying to use a shelve as a disc based dictionary, but have problems
> with nested lists. If I store a nested list as value, inner lists seem to
> be immutable.

It's a well-known but underdocumented defect of shelves whose
values are mutable objects -- mutations don't "take" unless you
take very specific steps to help.  I pointed it out both in the
Python Cookbook (official launch in 2 weeks, at OSCON) and in
the Nutshell (target date October), but that doesn't help much
right now:-).

Easiest way to reproduce the problem:

>>> import shelve
>>> s=shelve.open('x.y')
>>> s['a']=range(3)
>>> s['a']
[0, 1, 2]
>>> s['a'].append(4)
>>> s['a']
[0, 1, 2]
>>>

Workaround:

>>> x = s['a']
>>> x.append(4)
>>> s['a'] = x
>>> s['a']
[0, 1, 2, 4]
>>>

I.e. you must arrange to assign the new value to s[thekey] --
it's only on assignment to its items that the shelve object
notices any changes.


Proposed fixes mooted for Python 2.3 are probably not going
to happen.  Having s "cache" all the s[whatever] that are
being accessed (just in case they might be mutated) would, it
is felt, have enormous memory costs in the common case where
the objects are just being examined, not mutated.


> According to the library reference, shelves can store "essentially
> arbitrary Python objects" and "recursive data types".

They do.  They just don't give you exactly those objects when
you fetch s[x], but rather, copies (reconstructed from the
objects' pickles) -- and then promptly forget about whatever
they just returned (holding on to it might, it is felt, have
too-high memory costs).  So, when you call mutating methods
on s[whatever], you're mutating a copy -- the shelve object
still holds on to the original pickle, and if and when you
ask for s[whatever] again you'll get another fresh copy.
Notice...:

>>> s['a'] is s['a']
0
>>>

each s['a'] has different object identity, so "is" is not
satisfied.

> What is my misunderstanding?

I think you expect sensible behavior, sensible behavior is
hard to supply here, and the fact that shelve's behavior is
NOT sensible is not clearly documented anywhere (at least
until my books come out:-).

I also think this situation is exceedingly unfortunate.

Python and its libraries have VERY few gotchas that are at
all comparable to this veritable trap laid out for the
perfectly reasonable unwary user expecting perfectly reasonable
behavior.  This makes such traps stand out as _particularly_
troublesome when they do happen.

Unfortunately, I have no 'magic wand' fix that will both
make shelve's behavior reasonable AND still provide decent
performance in common use cases:-(.


Alex




More information about the Python-list mailing list