Advantages of UserDict class?

Viewed 26969

What are advantages of using UserDict class?

I mean, what I really get if instead of

class MyClass(object):
    def __init__(self):
        self.a = 0
        self.b = 0
...
m = MyClass()
m.a = 5
m.b = 7

I will write the following:

class MyClass(UserDict):
    def __init__(self):
        UserDict.__init__(self)
        self["a"] = 0
        self["b"] = 0
...
m = MyClass()
m["a"] = 5
m["b"] = 7

Edit: If I understand right I can add new fields to an object in a runtime in both cases?

m.c = "Cool"

and

m["c"] = "Cool"
4 Answers

It's tricky to overwrite dict correctly, while UserDict makes it easy. There was some discussion to remove it from Python3, but I believe it was kept for this reason. Example:

class MyDict(dict):

  def __setitem__(self, key, value):
    super().__setitem__(key, value * 10)


d = MyDict(a=1, b=2)  # Oups MyDict.__setitem__ not called
d.update(c=3)  # Oups MyDict.__setitem__ not called
d['d'] = 4  # Good!
print(d)  # {'a': 1, 'b': 2, 'c': 3, 'd': 40}

UserDict inherit collections.abc.MutableMapping, so don't have those drawback:

class MyDict(collections.UserDict):

  def __setitem__(self, key, value):
    super().__setitem__(key, value * 10)


d = MyDict(a=1, b=2)  # Good: MyDict.__setitem__ correctly called
d.update(c=3)  # Good: MyDict.__setitem__ correctly called
d['d'] = 4  # Good
print(d)  # {'a': 10, 'b': 20, 'c': 30, 'd': 40}

Well, as of 3.6 there are certainly some disadvantages, as I just found out. Namely, isinstance(o, dict) returns False.

    from collections import UserDict

    class MyClass(UserDict):
        pass

    data = MyClass(a=1,b=2)

    print("a:", data.get("a"))
    print("is it a dict?:", isinstance(data, dict))

Not a dict!

a: 1
is it a dict?: False

Change to class MyClass(dict): and isinstance returns True.

However... with UserDict you can step into its implementation.

(pdb-ing into functions/methods is an easy way to see exactly how they work)


#assumes UserDict

di = MyClass()

import pdb

#pdb will have work if your ancestor is UserDict, but not with dict
#since it is c-based
pdb.set_trace()
di["a"]= 1

Related