Working on Z3ECM code base i met following code construction:


try:
return self.applications[key]
except KeyError:
self.
applications[key] = PersistentList()
return self.applications[key]

where
applications is OOBTree.

My immediate reaction was to use standard python's mapping protocol method –
setdefault as «Readability counts» (C) and rewrite above long
code to following:


return self.__applications.setdefault(key, PersistentList())

nice, isn't it? and i was a bit surprised to get


AttributeError: 'BTrees._OOBTree.OOBTree' object has no attribute 'setdefault'


Of course setdefault can be easily emulated, but i want to have short
code :) You need to be aware that default argument instance will be created
each time you call setdefault, even if it won't be used.



So i raised question in zodb-dev mailing list about adding
setdefault method to ZODB and was kindly pointed by Dmitry Vasiliev
that this question was raised nearly a year ago -
http://mail.zope.org/pipermail/zodb-dev/2004-October/008040.html
and as a result it was frozen and no implementation was provided.



Currently some people came up that it's a good idea to have this method for
btrees, some had objections. Tim Peters showed how setdefault could
be emulated:

This one is obvious:


result = self.applications.get(key, None)
if result is None:
result = self.
applications[key] = PersistentList()
return result

While this one uses special btree's method insert:


self.applications.insert(key, PersistentList())
return self.
applications[key]

This time Jim Fulton gave +1 and as Tim noted: - «Jim's +1 wipes out any
number of -0 votes :) .»

So i made my hands dirty, created separate branch in ZODB and implemented
setdefault (of course in C :) Bit lately when reviewing my
branch Tim noted the behaviour(specific) of python's setdefault
doesn't fit well with BTree:


>>> d = {}
>>> d.setdefault(666)
>>> d
{666: None}

You see what's the point?

It will work only with OOBTree and IO, but not with OI, II, IF.

Tim proposed to have 2 required parameters to setdefault and that's
how it's now – you should explicitely pass default to method and this was
raised on python-dev too and seems like this behaviour will go into standard
python, because usage of setdefault without explicit default is
confusing and useless.



So, Tim mercilesly refactored my code, of course to make it better :),
thanks Tim.

As a result branch is now merged and we have setdefault method in
ZODB3.5 final, so you can use it with Zope3 now (currently with 3.1 branch
and soon with trunk) and write short, readable code, though, of course,
someone may argue :)



More to come...

(Post originally written by Ruslan Spivak on the old Nuxeo blogs.)