[python]Collections模块介绍

Collections模块中的每一个类都是为了补充python内置数据类型list和dict的功能,在某些特性情况下使用Collections中的类将取得更好的效果。

Collections模块中所包含的类:

namedtuple()factory function for creating tuple subclasses with named fields
dequelist-like container with fast appends and pops on either end
ChainMapdict-like class for creating a single view of multiple mappings
Counterdict subclass for counting hashable objects
OrderedDictdict subclass that remembers the order entries were added
defaultdictdict subclass that calls a factory function to supply missing values
UserDictwrapper around dictionary objects for easier dict subclassing
UserListwrapper around list objects for easier list subclassing
UserStringwrapper around string objects for easier string subclassing

namedtuple(对tuple的扩展)

应用需求:我们知道tuple中的元素只能通过元素在tuple中的位置进行索引,最大的问题是元素的位置很难与元素的真实含义相结合,毕竟代码是要让人看得懂的。如果tuple中元素太多将对代码维护造成极大的挑战。

namedtuple就是为了解决上面提到的痛点,通过给tuple中的元素赋予一个名字——可以认为是key,通过key来访问value,这样就能解决位置索引给阅读代码者造成的烦恼。

collections.namedtuple(typename, field_names, *, verbose=False, rename=False, module=None)

typename是namedtuple类的名字——一个字符串,我们习惯将namedtuple返回值的名字设成与typename相同typename要以字符串的形式表示。执行namedtuple(typename, field_names)后会返回一个tuple子类,每个元素的别名用field_names中的字符串来命名。

field_names是tuple元素的别名——可以认为是key,这样可以避免使用位置去索引tuple元素。field_names由多个field_name构成,每个field_name必须为字符串。field_name可以通过两种方式来构成field_names,一种是将全部field_name装入list中(['a','b','c','d']),另外一种是将field_name全部装入一个字符串中,field_name之间用分隔符(空格,逗号,tab)隔开('a b c d'或者'a,b,c')。特别要注意的是,namedtuple生成的是一个类,而不是对象

>>> Point1 = namedtuple('Point','x,y,z')
>>> Point2 = namedtuple('Point','x y z')
>>> Point3 = namedtuple('Point',['x', 'y', 'z'])

生成namedtuple类后需要实例化对象namedtuple类在初始化的时候有几个别名,实例化的时候就需要提供几个参数。既可以直接带入参数,也可以以“别名=值”的方式实例化对象。

>>> p=Point1(1,2,3)
>>> p
Point(x=1, y=2, z=3)
>>> q=Point(z=33,y=22,x=11)
>>> q
Point(x=11, y=22, z=33)

classmethod somenamedtuple._make(iterable)

除了上面提到的初始化方法,还可以通过iterable来实例化对象。

>>> Point
<class '__main__.Point'>
>>> p=Point._make([11,12,13])
>>> p
Point(x=11, y=12, z=13)

这个函数的好处是,可以自动给namedtuple对象赋值,也就意味着可以把_make()函数作为其它函数的输入参数(工厂方法)。

EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')

import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
    print(emp.name, emp.title)

somenamedtuple._asdict()

返回一个OrderedDict,其中的键值对是namedtuple中的别名及其对应的值。

>>> p
Point(x=11, y=12, z=13)
>>> p._asdict()
OrderedDict([('x', 11), ('y', 12), ('z', 13)])

somenamedtuple._replace(kwargs)

实例化namedtuple对象后,如果想替换某些元素的值,可以使用_replace方法。

>>> p
Point(x=11, y=12, z=13)
>>> p._replace(x=33)
Point(x=33, y=12, z=13)

可以使用拆包的方式作为_replace()的参数。

>>> p
Point(x=11, y=12, z=13)
>>> new_point = {'x':100,'y':101,'z':102}
>>> p._replace(**new_point)
Point(x=100, y=101, z=102)

>  somenamedtuple._fields

返回全部tuple元素的别名。

>>> p._fields            # view the field names
('x', 'y')

>>> Color = namedtuple('Color', 'red green blue') # Three tuple: red, green, blue
>>> Pixel = namedtuple('Pixel', Point._fields + Color._fields) # Five tuple: x,y,red,green,blue
>>> Pixel(11, 22, 128, 255, 0)
Pixel(x=11, y=22, red=128, green=255, blue=0)

如果只想得到namedtuple对象中某个属性的值,可以使用内置函数getattr(),或者者直接使用“点”符号。

>>> p
Point(x=11, y=12, z=13)
>>> getattr(p,'z')
13
>>> getattr(p,'y')
12
>>> p.x
11

 

deque(对list的扩展)

应用需求:queue数据结构的数据是先进先出——只能从一个方向插入数据,从另一侧排出数据。如果希望两边都可以pop数据,可以使用deque数据结构。deque的全称是“double-ended queue”。

class collections.deque([iterable[, maxlen]])

返回deque对象,其中的元素是iterable。如果iterable为空,则返回一个空的deque对象。

maxlen指定deque的最大长度,如果没有指定该参数的值,deque可以无限增长。如果iterable的长度比maxlen大,后进入的数据会把先进入的“挤出去”,直到iterable被全部遍历

>>> deque(range(10))
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> deque(range(100),10)  #限定长度后,后进的会把先进的“挤出去”
deque([90, 91, 92, 93, 94, 95, 96, 97, 98, 99], maxlen=10)

正如list有append、extend、clear、remove、insert、pop、reverse方法一样,deque也有上面提到的方法,除了这些方法外,还有一些是deque数据结构特有的。

appendleft(x)

功能类似append(),只不过是在左侧开始位置添加参数x。

extendleft(iterable)

功能类似extend(),只不过是在左侧开始位置添加iterable。

popleft()

功能类似pop(),只不过是把左侧开始位置的数据“挤出去”,并返回该值。

rotate(n)

将deque中的全部元素循环右移n位。如果n是负数,则循环左移n位。

maxlen

返回deque对象中maxlen的值,如果deque没有设定maxlen参数,返回None。

 

ChainMap(对dict的扩展)

应用对象:将多个dict整合到同一个列表中,存在一个key对应多个value的情况(多个dict中存在相同的key),以第一个出现的k键值对为准,后面出现的将被忽略。

> class collections.ChainMap(*maps)

返回一个ChainMap对象(可以认为是一个list,其中的元素全部都是maps对象(dict))。其中,如果maps为空,ChainMap中只有一个空的dict;如果map不为空,ChainMap保存的是全部maps对象。

>>> x = {'b': 10, 'c': 11}
>>> y = {'a': 1, 'b': 2}
>>> z = ChainMap(x, y)
>>> z
ChainMap({'b': 10, 'c': 11}, {'a': 1, 'b': 2})
>>> ChainMap()
ChainMap({})

关于ChainMap对象,有几点需要说明一下:

  • 查询ChainMap键值对的方式与dict一样,不同的地方是ChainMap会遍历列表中的全部dict,直到遇到第一个键值对。如果查询的键值对不存在,会抛出KeyError异常
>>> z
ChainMap({'b': 10, 'c': 11}, {'a': 1, 'b': 2})
>>> z['b']
10
>>> z['a']
1
>>> z['e']
    raise KeyError(key)
KeyError: 'e'
  • 修改键值对的方式与dict一样,不同的是只会修改ChainMap列表中的第一个dict,从下面的列子可知,当修改key['b']=100的时候,只会修改列表中的一个dict;新增键值对key['a']=101的时候,只在第一个dict中增加了该键值对
>>> z
ChainMap({'b': 10, 'c': 11}, {'a': 1, 'b': 2})
>>> z['b']=100
>>> z['a']=101
>>> z
ChainMap({'b': 100, 'c': 11, 'a': 101}, {'a': 1, 'b': 2})

正如Python Documentation中所描述的:

Lookups search the underlying mappings successively until a key is found. In contrast, writes, updates, and deletions only operate on the first mapping.

  • dict中的方法在ChainMap中可以被正常使用,需要注意的是items()方法,该方法会返回一个由key和value构成的tuple。由于ChainMap中相同key可能会存在多个value,为了避免冲突,原则还是以第一个出现的键值对为准
>>> z.items()
ItemsView(ChainMap({'b': 100, 'c': 11, 'a': 101}, {'a': 1, 'b': 2}))
>>> list(z.items())
[('b', 100), ('c', 11), ('a', 101)]

> maps

将ChainMap以list方式返回,体现出ChainMap本质上是装着多个dict的列表

>>> z
ChainMap({'b': 100, 'c': 11, 'a': 101}, {'a': 1, 'b': 2})
>>> z.maps
[{'b': 100, 'c': 11, 'a': 101}, {'a': 1, 'b': 2}]

> new_child(m=None)

返回一个新的ChainMap,第一个元素是m,后面紧跟着原来的dict列表。如果new_child()函数为空,则新ChainMap的第一个dict为空。

>>> z.new_child()  # First dict is empty
ChainMap({}, {'b': 100, 'c': 11, 'a': 101}, {'a': 1, 'b': 2})
>>> z.new_child({'a': 1, 'b':2})   # First dict is new
ChainMap({'a': 1, 'b': 2}, {'b': 100, 'c': 11, 'a': 101}, {'a': 1, 'b': 2})

> parents

返回ChainMap中第二个及之后的dict,第一个dict将被忽略

>>> z
ChainMap({'b': 100, 'c': 11, 'a': 101}, {'a': 1, 'b': 2})
>>> z.parents
ChainMap({'a': 1, 'b': 2})

 

Counter(对dict的扩展)

应用对象:统计list或iterable中每个元素出现的次数,返回Counter对象,其中包含元素和元素的次数为键值对的字典。

class collections.Counter([iterable-or-mapping])

如果想统计list中元素出现的次数,一个非常简单的方式是使用Counter(),如下面的例子:

>>> Counter(['red', 'blue', 'red', 'green', 'blue', 'blue'])
Counter({'blue': 3, 'red': 2, 'green': 1})
>>> Counter('aaaffereffswfwgffdfsdf')
Counter({'f': 9, 'a': 3, 'e': 2, 's': 2, 'w': 2, 'd': 2, 'r': 1, 'g': 1})

生成Counter对象后,可以调用list、set、tuple、dict生成对应类型的数据。

>>> dict(Counter('aaaffereffswfwgffdfsdf'))
{'a': 3, 'f': 9, 'e': 2, 'r': 1, 's': 2, 'w': 2, 'g': 1, 'd': 2}
>>> list(Counter('aaaffereffswfwgffdfsdf'))
['a', 'f', 'e', 'r', 's', 'w', 'g', 'd']
>>> set(Counter('aaaffereffswfwgffdfsdf'))
{'r', 'd', 's', 'e', 'f', 'g', 'a', 'w'}
>>> dict(Counter('aaaffereffswfwgffdfsdf'))
{'a': 3, 'f': 9, 'e': 2, 'r': 1, 's': 2, 'w': 2, 'g': 1, 'd': 2}
>>> c.items()
dict_items([('a', 3), ('f', 9), ('e', 2), ('r', 1), ('s', 2), ('w', 2), ('g', 1), ('d', 2)])

> elements()

生成Counter对象后,如果想知道全部的key,使用elements()。

>>> c
Counter({'f': 9, 'a': 3, 'e': 2, 's': 2, 'w': 2, 'd': 2, 'r': 1, 'g': 1})
>>> c.elements()
<itertools.chain object at 0x01FFC250>
>>> list(c.elements())
['a', 'a', 'a', 'f', 'f', 'f', 'f', 'f', 'f', 'f', 'f', 'f', 'e', 'e', 'r', 's', 's', 'w', 'w', 'g', 'd', 'd']

most_common([n])

生成Counter对象后,有种情况是键值对太多,我们只在乎出现频率最高的几项,可以使用该方法,参数n代表前n个最常出现的键值对。

>>> c
Counter({'f': 9, 'a': 3, 'e': 2, 's': 2, 'w': 2, 'd': 2, 'r': 1, 'g': 1})
>>> c.most_common(3)
[('f', 9), ('a', 3), ('e', 2)]

>>> # Find the ten most common words in Hamlet
>>> import re
>>> words = re.findall(r'\w+', open('hamlet.txt').read().lower())
>>> Counter(words).most_common(10)
[('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),
 ('you', 554),  ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]

 

OrderedDict(对dict的扩展)

应用需求:我们知道dict中的键值对是“无序”存放的,有时候我们却希望dict中键值对按照插入的先后顺序排列,此时就可以使用OrderDict类。

class collections.OrderedDict([items])

输入参数是item类型,即(key, value)构成的tuple,返回值是有序字典。如果items中存在一个key对应多个value,只会保存第一个出现的键值对,后面的会被忽略。

>>> s
[('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
>>> OrderedDict(s)
OrderedDict([('red', 1), ('blue', 4)])

如果不带参数,将创建一个空的OrderedDict对象,可以像字典的处理方式给OrderedDict添加对象。先被插入的键值对将放到后被插入的前面,这正是有序字典的特点。

>>> a=OrderedDict()
>>> a
OrderedDict()
>>> a['red']=1
>>> a['blue']=2
>>> a
OrderedDict([('red', 1), ('blue', 2)])

将OrderedDict对象作为list、set、dict的参数,可以转化为对应的类型。

>>> a
OrderedDict([('red', 1), ('blue', 2)])
>>> dict(a)
{'red': 1, 'blue': 2}
>>> list(a)
['red', 'blue']
>>> set(a)
{'blue', 'red'}
>>> a.items()
odict_items([('red', 1), ('blue', 2)])

 

defaultdict(对dict的扩展)

应用需求:当key不存在时,dict会返回一个找不到key时的方法,比如list、set、int、float等等,而不是当找不到key时抛出KeyError异常。

class collections.defaultdict([default_factory[, ...]])

default_factory表示工厂方法,使用defaultdict将创建(返回)一个字典,字典的值都是default_factory类型。一般我们会把default_factory设成list或set,将数据保存到list或set中。下面的例子是将default_factory设成list,然后把相同key的value保存一起。

>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
>>> d = defaultdict(list)
>>> for k,v in s:
	d[k].append(v)

>>> d
defaultdict(<class 'list'>, {'red': [1, 3, 1], 'blue': [2, 4, 4]})

 

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值