前言
Python 内置模块collections, 目标是提供各种专门的集合数据类型来解决特定的编程问题。
本系列介绍其中的数据结构特点和使用方法, 以便遇到某些特定的问题,可以找到对应的数据来处理, 达到事半功倍的效果
其他的可以参考
Python中的collections模块(一) 使用Counter,pythonic的对象计数方式
Python中的collections模块(二) 有序字典OrderedDict和链接字典ChainMap
Python中的collections模块(三) 命名元组namedtuple和双端队列deque
为什么要使用UserString,UserList,UserDict
编码中有时你需要自定义内置类型,例如字符串、列表和字典,以添加和修改某些行为。大部分时候可以直接对这些类型进行子类化来实现。
但是有的时候会发现, 子类化的实例并不像预期中那样表现, 因为Python对内置类型的设计和实现考虑到了开闭原则(对扩展开放,但对修改关闭)。
例如, 我需要创建一个在插入键时自动将键转为小写的字典。
可以通过子类化dict并
覆盖.__setitem__()
函数, 每次插入键时将键名转为小写:
In [1]: class LowerDict(dict):
...: def __setitem__(self, key, value):
...: key = key.lower()
...: super().__setitem__(key, value)
In [2]: data = LowerDict({'FIRST': 1, 'SECOND': 2})
In [3]: data['THIRD'] = 3
In [4]: data.update({'FOURTH': 4})
In [5]: data
Out[5]: {'FIRST': 1, 'SECOND': 2, 'third': 3, 'FOURTH': 4}
可以看到,只有使用 [ ] 为字典赋值时的THIRD被转成了小写, 而调用update和初始化函数时, 转小写并没有生效。必须要覆盖这两个方法才可以
In [6]: class LowerDict(dict):
...: def __init__(self, data):
...: data = {k.lower(): v for k, v in data.items()}
...: super().__init__(data)
...: def __setitem__(self, key, value):
...: key = key.lower()
...: super().__setitem__(key, value)
...: def update(self, data):
...: data = {k.lower(): v for k, v in data.items()}
...: super().update(data)
使用UserDict
使用UserDict作为父类来实现上述功能。
In [16]: class LowerDict(UserDict):
...: def __setitem__(self, key, value):
...: key = key.lower()
...: super().__setitem__(key, value)
...:
In [17]: data = LowerDict({"FIRST": 1, "SECOND": 2})
In [18]: data["THIRD"] = 3
In [19]: data.update({'FOURTH': 4})
In [20]: data
Out[20]: {'first': 1, 'second': 2, 'third': 3, 'fourth': 4}
结论:
当需要一个与底层包装的内置类几乎相同的类并且您想要自定义其标准功能的某些部分时,应该使用UserDict
, UserList
, 和UserString
。