Python中UserDict类的优点

leg*_*esh 16 python oop

使用UserDict类有什么好处?

我的意思是,如果不是,我真的得到了什么

class MyClass(object):
    def __init__(self):
        self.a = 0
        self.b = 0
...
m = MyClass()
m.a = 5
m.b = 7
Run Code Online (Sandbox Code Playgroud)

我会写以下内容:

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

编辑:如果我理解正确,我可以在两种情况下都在运行时向对象添加新字段?

m.c = "Cool"
Run Code Online (Sandbox Code Playgroud)

m["c"] = "Cool"
Run Code Online (Sandbox Code Playgroud)

Ale*_*lli 34

UserDict.UserDict自从Python 2.2以来没有实质性的附加值,因为正如@gs所提到的,你现在可以dict直接子类- 它只是为了向后兼容Python 2.1及更早版本,当内置类型不能是子类时.尽管如此,它仍保留在Python 3中(现在在collections模块中的适当位置),正如文档现在提到的那样,

直接从dict子类化的能力部分取代了对这个类的需求; 但是,这个类可以更容易使用,因为底层字典可以作为属性访问.

UserDict.DictMixin在Python 2中,非常方便 - 正如文档所说,

该模块定义了一个mixin,DictMixin,为已经具有最小映射接口的类定义所有字典方法.这极大地简化了编写需要替代字典的类(例如搁置模块).

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

在Python 3中,DictMixin已经不见了; 您可以通过依赖(或仅用于R/O映射)获得几乎相同的功能.它更优雅,虽然不是很方便(看到这个问题,关闭时"不会修复";简短的讨论值得一读).collections.MutableMappingcollections.Mapping

  • 因为09年的事情在python 3中有点移动,而DictMixin又回来了:http://docs.python.org/library/userdict.html#UserDict.DictMixin - 虽然MutableMapping确实适用于大多数用途. (7认同)
  • 这仍然有效吗?阅读"Fluent Python",作者建议继承UserDict,因为"主要警告:内置函数的代码(用C编写)不会调用由用户定义的类覆盖的特殊(魔术)方法".这本书涵盖了3.x但这个警告不适用于2.7吗? (7认同)
  • 我在官方 Python 3 文档 https://docs.python.org/3/library/collections.html#collections.UserDict 中看到了 UserDict,但没有看到任何有关 MutableMapping 的内容。最有可能的是,答案已经过时了。 (3认同)
  • @Stefano:现在还没有,我很确定在Python 3的标准库中没有任何DictMixin.您提供的链接当时是Python 2.7.2文档的链接(目前为404). (2认同)

Geo*_*lly 7

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

顺便说一句:在最近的Python版本中,你可以dict直接子类化,你不需要UserDict.


Con*_*tor 7

正确覆盖很困难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}
Run Code Online (Sandbox Code Playgroud)

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}
Run Code Online (Sandbox Code Playgroud)


JL *_*ret 5

嗯,正如我刚刚发现的那样,从 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))

Run Code Online (Sandbox Code Playgroud)

不是字典!

a: 1
is it a dict?: False
Run Code Online (Sandbox Code Playgroud)

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

但是...使用 UserDict 您可以逐步实现它。

(pdb-ing 到函数/方法中是了解它们如何工作的简单方法)


#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

Run Code Online (Sandbox Code Playgroud)