Python中UserDict类的优点

时间:2009-09-08 07:00:18

标签: python oop

使用 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"

4 个答案:

答案 0 :(得分:34)

自从Python 2.2以来,

UserDict.UserDict没有实质性的附加值,因为正如@gs所提到的,你现在可以直接将dict子类化 - 它只是为了向后兼容Python 2.1和更早版本,当内置时类型不能是子类。仍然,它保存在Python 3中(现在在collections模块中的适当位置),因为the docs现在提到,

  

这门课程的必要性   部分取代了能力   直接来自dict的子类;然而,   这个类可以更容易使用   因为基础字典是   可作为属性访问。

在Python 2中,

UserDict.DictMixin非常方便 - 正如文档所说,

  

该模块定义了一个mixin,DictMixin,   定义所有字典方法   已经有最低限度的课程   映射界面。这很大   简化了编写需要的类   可以替代字典   (例如搁置模块)。

你对它进行了子类化,定义了一些基本方法(至少为__getitem__,这对于只读映射而言是足够的,无法获取键或迭代;如果你需要这些能力,也可以keys;可能__setitem__,你有一个R / W映射,但没有删除项目的能力;添加__delitem__以获得完整的功能,并可能出于性能原因覆盖其他方法),并得到一个完整的实现dict丰富的API(updateget等)。 Template Method设计模式的一个很好的例子。

在Python 3中,DictMixin消失了;您可以依靠collections.MutableMapping(或仅collections.Mapping进行R / O映射)来获得几乎相同的功能。它更优雅,虽然不是很方便(见this issue,关闭时“不会修复”;简短的讨论值得一读。)

答案 1 :(得分:7)

对dict进行子类化为您提供了dict的所有功能,例如if x in dict:。如果你想扩展dict的功能,例如创建一个有序的dict,你通常会这样做。

BTW:在最新的Python版本中,您可以直接子类dict,但不需要UserDict

答案 2 :(得分:3)

嗯,正如我刚刚发现的那样,从3.6版本开始肯定存在一些缺点。即,isinstance(o, dict)返回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))

不是命令!

a: 1
is it a dict?: False

更改为class MyClass(dict):,然后isinstance返回True。

但是...通过UserDict,您可以逐步实施它。

(pdb-进入函数/方法是一种准确了解它们如何工作的简单方法)


#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

答案 3 :(得分:0)

正确覆盖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}