UserDict's has_key() and get() should use __getitem__()

Hamish Lawson hamish_lawson at yahoo.co.uk
Wed Apr 5 06:44:01 EDT 2000


[This is a modified version of an earlier posting for which I
didn't get any responses. I'm trying again with what I'm hoping
might be a clearer exposition.]

The UserDict class in the standard library provides a framework
for defining your own dictionary-like classes. However I think
their may be an anomaly in how it is currently implemented (up
to 1.5.2). I think that most people would expect that if the
following statement succeeded:

    print d['Joe']

then the following line would evaluate true:

    print d.has_key('Joe')

However, under the current implementation of UserDict, if you
redefine __getitem__() in your own UserDict-derived class, you
will probably also have to redefine has_key() and get() (and
maybe others) in order to have them behave as expected. This
wholescale redefining is caused by the fact that UserDict's
has_key() and get() methods don't make use of the class's own
__getitem__() method in determining whether a key exists, as
shown in the extract below:

    def __getitem__(self, key):
        return self.data[key]
    def has_key(self, key):
        return self.data.has_key(key)
    def get(self, key, failobj=None):
        return self.data.get(key, failobj)

My contention is that the behaviour we expect from get() and
has_key() is intimately bound up with how __getitem__() behaves,
and this should be reflected in get() and has_key() making use
of __getitem__():

    def has_key(self, key):
        try:
            self[key]
            return 1
        except KeyError:
            return 0
    def get(self, key, failobj=None):
        try:
            return self[key]
        except KeyError:
            return failobj

It is now possible to redefine __getitem__() in a derived class
and have has_key() and get() behave as expected, without having
to redefine them also.

(It may be that other methods in UserDict should also be
reimplemented along these lines - I've not looked yet.)

Is there some reason why this isn't the right thing to do?
Assuming it is, I'd like to get this change into Python 1.6.

Hamish Lawson

-----------------------------------------------------------

PS: Below is an example demonstrating how the semantics of
has_key() and get() get broken under the current version of
UserDict when you redefine only __getitem__() in a derived class.


    import UserDict, string

    class CaselessDict(UserDict):
        "A dictionary class with case-insensitive keys"

        def __setitem__(self, key, value):
            self.data[string.lower(key)] = value

        def __getitem__(self, key):
            return self.data[string.lower(key)]


    d = CaselessDict()
    d['Joe'] = "Sue"
    print d['jOE']             # prints "Sue"
    print d.has_key('jOE')     # prints 0 but expected 1
    print d.get('jOE', None)   # prints None but expected "Sue"


* Sent from RemarQ http://www.remarq.com The Internet's Discussion Network *
The fastest and easiest way to search and participate in Usenet - Free!




More information about the Python-list mailing list