Python和字典类似的对象
我需要一个适用于 Python 3.1 的深度更新函数,这个函数可以递归地更新一个字典里的子字典,也就是可以更新父字典里面的所有子字典。
不过,我觉得将来我的这个函数可能还需要处理一些看起来像字典但其实不是的对象。而且,我想避免使用 isinstance
和 type
,因为我在几乎每个 Python 爱好者的博客上都看到这些被认为是不好的做法。
但是鸭子类型是 Python 的一种哲学,那我该怎么检查一个对象是否像字典呢?
谢谢大家!
补充:感谢大家的回答。为了以防万一,我写的这个函数可以在这里找到: http://blog.cafeaumiel.com/public/python/dict_deep_update.py
6 个回答
鸭子类型是一种编程方式,你可以按照自己的想法去做事情,如果你的对象表现得和你预期的不一样,那就处理后果。
比如,你想检查某个东西是不是像字典那样的,如果是的话就更新它,对吧?那你就直接调用这个对象的更新方法,如果没有这个方法,就处理一下出现的错误。
当然,如果你碰到的是自定义类的对象,而这些对象的更新方法做的事情完全不同,那就可能会有问题——我也不太确定该怎么处理这种情况。
使用 isinstance
是没问题的,它在需要递归的代码中经常被用到。
如果你说的字典样式是指这个对象的类是从 dict
继承来的话, isinstance
也会返回 True
。
>>> class A(dict):
pass
>>> a = A()
>>> isinstance(a, dict)
True
可以看看在3.x版本中新加入的抽象基类(ABC)在collections模块里的内容:
http://docs.python.org/3.1/library/collections.html
我建议用isinstance来检查是否是Mapping,就像下面这样:
>>> import collections
>>> isinstance({},collections.Mapping)
True
然后,如果你自己创建一个类似字典的类,可以把collections.Mapping作为它的基类之一。
另一种方法是尝试执行字典操作,并捕获可能出现的异常,但考虑到你提到的递归,我更倾向于先检查基础类型,而不是处理哪个字典、子字典或其他字典成员存在或不存在导致的异常。
补充说明:检查Mapping ABC而不是直接检查dict的好处在于,这样的测试可以适用于所有类似字典的类,无论它们是否继承自dict,因此更灵活,以防万一。