A cautionary tale

Steven D'Aprano steve at pearwood.info
Thu Dec 5 03:06:13 EST 2013


On Wed, 04 Dec 2013 11:16:40 +0200, Frank Millman wrote:

[...]
> Then I noticed that certain changes were not being written back to the
> database. After some investigation, I found the error in a part of my
> program that I have not had to look at for ages. When reading data in
> from the database, I preserve a copy of the original value. When saving,
> I compare that to the current value when deciding which columns need
> updating. I do this in the obvious way -
> 
>     on reading -
>         orig_value = value

As you know, that is not the obvious way to create a copy. That binds a 
new name to the same value. To create a copy, you need:

orig_value = copy.copy(value)

or for lists:

orig_value = value[:]

I think we've all made the same mistake you have, it's an easy mistake to 
make, but for an experienced Python code it should also be an easy 
mistake to identify. Mind you, tracking it down might take a while...


>     on saving -
>        if value != orig_value:
>             this one needs updating
> 
> Have you spotted the deliberate mistake yet? In the case of a JSON list,
> orig_value and value point to the same, mutable, list. So when I compare
> value with orig_value, they are always the same, whether changes have
> been made or not!
> 
> The obvious answer is to store a copy of the list. It was not so obvious
> where to make the change, as there were other implications. Eventually I
> decided to over-ride the 'getter' for the JSON type, and return
> copy(value) instead of value. That way if it is changed and then put
> back using the 'setter', the two objects are no longer equal. I have
> made that change, done some more testing, and for now it seems ok.

I wouldn't do it that way. To my mind, the most obvious way of handling 
this is to add a "changed" flag to the object, and ensure that any 
modifications set the flag.

Of course, that may end up being more work than the way you've done it, 
but it will save making potentially many copies of objects which don't 
need to be copied.


> So have the last couple of days been a waste of time? I don't think so.
> Is the program a bit cleaner and conceptually sounder? I hope so.
> 
> Why am I telling you all this? No particular reason, just thought some
> of you might find it interesting.

Thank you for sharing your experiences with us!



-- 
Steven



More information about the Python-list mailing list