UserDict类的优点是什么?
使用UserDict
类有什么好处呢?
我的意思是,如果我不使用下面的代码:
class MyClass(object):
def __init__(self):
self.a = 0
self.b = 0
...
m = MyClass()
m.a = 5
m.b = 7
而是写成这样:
class MyClass(UserDict):
def __init__(self):
UserDict.__init__(self)
self["a"] = 0
self["b"] = 0
...
m = MyClass()
m["a"] = 5
m["b"] = 7
补充:如果我理解得没错的话,在这两种情况下,我都可以在运行时给对象添加新字段,对吗?
m.c = "Cool"
还有
m["c"] = "Cool"
5 个回答
正确地覆盖 dict
是有点棘手的,但使用 UserDict
就简单多了。曾经有人讨论要把它从 Python3 中去掉,但我觉得保留它是有原因的。下面是一个例子:
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
继承了 collections.abc.MutableMapping
,所以没有那些缺点:
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}
把字典(dict)进行子类化可以让你拥有字典的所有功能,比如可以用 if x in dict:
来检查某个值是否在字典里。通常你这么做是为了扩展字典的功能,比如创建一个有序字典。
顺便说一下,在更新版的Python中,你可以直接对子类化 dict
,不需要使用 UserDict
了。
UserDict.UserDict
从 Python 2.2 开始就没有太大用处了,因为正如 @gs 提到的,现在你可以直接继承 dict
了。它的存在主要是为了兼容 Python 2.1 及更早的版本,那时候内置类型不能被继承。不过,它在 Python 3 中仍然保留了(现在在 collections
模块中),因为正如文档所说,
这个类的需求部分被直接从 dict 继承的能力所取代;然而,这个类可能更容易使用,因为底层的字典可以作为一个属性访问。
UserDict.DictMixin
在 Python 2 中非常实用——正如文档所说,
这个模块定义了一个混合类 DictMixin,为已经有最基本映射接口的类定义了所有字典方法。这大大简化了需要替代字典的类的编写(比如 shelve 模块)。
你可以继承它,定义一些基本方法(至少要有 __getitem__
,这足以实现只读映射,不能获取键或迭代;如果需要这些功能,还要定义 keys
;可能还需要 __setitem__
,这样就有了读写映射,但不能删除项目;如果想要完整功能,可以加上 __delitem__
,并可能为了性能重写其他方法),这样就能实现 dict
丰富的 API(如 update
、get
等)。这是一个很好的 模板方法设计模式的例子。
在 Python 3 中,DictMixin
被移除了;你可以通过依赖 collections.MutableMapping
来获得 几乎 相同的功能(或者仅使用 collections.Mapping
来实现只读映射)。虽然这种方式更优雅,但使用起来没有那么方便(可以看看这个问题,它被关闭时的回复是“不会修复”;短暂的讨论值得一读)。