10.8 模块:collections

简介

collections是Python内建的一个集合模块,其中提供了许多有用的集合类。

注意:使用这些类的时候要先从collections模块导入

from collections import XXX

 

namedtuple

一个点的二维坐标可以表示为:

p=(1,2)

但是,看到(1,2),很难看出这个tuple是用来表示一个坐标的。

定义一个class又小题大做了,这时,namedtuple就派上了用场:

from collections import namedtuple
Point=namedtuple('Point',['x','y'])
p=Point(1,3)
print (p.x,p.y)

1 3

namedtuple是一个函数,它用来创建一个自定义tuple对象,并且规定了tuple元素的个数,并且可以用属性而不是索引来引用tuple的某个元素。

这样,我们用namedtuple定义了一种数据类型,它具备tuple的不变性,又可以根据属性来引用,使用十分方便。

简单理解,namedtuple函数创建了一个继承自tuple的子类,该子类的名字即为namedtuple赋值号左边的那个(如上文的Point = namedtuple(...)的左边的Point),该子类的属性确定,且名字为namedtuple第二个参数List的中的字符串元素。但是通过属性引用时,如p.x不带字符串引号

可以验证Point是tuple的子类

isinstance(p,Point)
True
isinstance(p,tuple)
True

类似的,要用圆心坐标和半径表示一个圆:

Circle=namedtuple('Circle',['x','y','r'])
c=Circle(1,2,3)#圆心(1,2) 半径3的圆

补充:namedtuple的第一个参数应该为类名称,但是实际上,该项取值可以随意,创建对象时,只用到了namedtuple左边那个名称(如上文的Circle = namedtuple(...)的Circle)。

 

deque

使用List存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为List是线性存储(类似数组),数据量大的时候,插入和删除效率很低。

deque是为了实现高效插入和删除的双向List,适合用于队列和栈

用法和List很类似,除了实现了List的append()、pop()外,还支持appendleft()popleft()。这样可以很高效地往头部添加或删除元素。

q=deque(['a','b','c'])
q.append('x')
q.appendleft('y')

q
deque(['y', 'a', 'b', 'c', 'x'])

 

defaultdict

使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望Key不存在时,返回一个默认值,就可以用defaultdict:

dd=defaultdict(lambda:'N/A')
dd['Key1']='abc'

dd['Key1']
'abc'
dd['Key2']
'N/A'

注意:默认值是调用函数返回的,而函数在创建defaultdict对象时作为参数传入。

除了在Key不存在时返回默认值,defaultdict的其他行为和dict是完全一样的。

 

OrderedDict

使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序(注意是保持Key创建时候的次序,而非大小顺序)。

如果要保持Key的顺序(注意①是Key而不是Value②是创建次序非大小顺序),可以用OrderedDict

from collections import OrderedDict
d=dict(a=1,c=3,b=2)
od=OrderedDict(a=1,c=3,b=2)

od
OrderedDict([('a', 1), ('c', 3), ('b', 2)])
list(od.keys())
['a', 'c', 'b']

 

ChainMap

ChaimMap可以把一组dict串起来并组成一个逻辑上的dictChainMap本身也是一个dict,但查找的时候,会按照顺序在内部的dict依次查找。

什么时候使用ChainMap最合适?举个例子:应用程序往往都需要传入参数,参数可以通过①命令行传入,可以通过②环境变量传入,还可以有③默认参数。我们可以用ChainMap实现参数的优先级查找,即先查命令行参数,如果没有传入,再查环境变量,最后再用默认参数。

下面的代码演示了如何查找usercolor两个参数:

#构造命令行参数:
parser=argparse.ArgumentParser()
parser.add_argument('-u','--user')
parser.add_argument('-c','--color')
namespace=parser.parse_args()
command_line_args={k:v for k,v in vars(namespace).items() if v}

#组合构成ChainMap
combined=ChainMap(command_line_args,os.environ,defaults)

print('color=%s'%combined['color'])
print('user=%s'%combined['user'])

 补充:

ChianMap的作用是对多个字典dict进行链接,如上文combined=ChainMap(command_line_args,os.environ,defaults)。把字典command_line_args、os.environ、defaults三个dict对象绑定在一起变成了一个所有字典总和的大字典,但这不等于字典的简单拼接!与普通字典拼接最大的区别在于该大字典中能够保存一样的建Key!当你用被重复的Key去访问Value的时候,得到的一定是在大字典里位置靠前的Value,被链接起来的字典会因为排序的不同而产生优先级

 

Counter

Counter是一个简单的计数器

 

from collections import Counter
c=Counter()
for ch in 'programming':
    c[ch]+=1

c
Counter({'r': 2, 'g': 2, 'm': 2, 'p': 1, 'o': 1, 'a': 1, 'i': 1, 'n': 1})

c.update('hello')#用'hello'更新c
c
Counter({'r': 2, 'o': 2, 'g': 2, 'm': 2, 'l': 2, 'p': 1, 'a': 1, 'i': 1, 'n': 1, 'h': 1, 'e': 1})

 

总结:

一共讲了五种collections模块的类:

namedtuple、deque、defaultdict、Ordereddict、ChainMap

实际上可以用的类不止这五种。

namedtuple:

实际上定义了一种只有属性简易类,该类继承自tuple

例一:坐标类

Point = namedtuple('Point' , ['x','y'])

该类的名字为namedtuple赋值号左边的那个(比如Point),属性为namedtuple第二个参数list中的。

from collections import namedtuple

Point = namedtuple('P',['x','y'])
Circle = namedtuple('C' , ['x' , 'y' , 'r'])

P=Point(1,2)
P.x
1
C=Circle(1,2,3)
C.r
3

进行类型检测时,可以发现这些对象既属于创建它们时候的,又属于tuple(这是自然,因为它们都继承自tuple)。

 

deque:

List比较类似数据结构中的数组,访问很方便但插入删除不便。

deque为是为了实现高效增删双向List,可以用来构建队列(当然,也可用queue模块中的Queue类,也是Python内置的队列类)。

deque在List的基础上实现了apppendleftpopleft,即可以从进行增删。普通的List的appendpop是在尾部的增删。

d=deque(['1','2','3'])

 

ChainMap

将多个字典链接到一块,当多个字典中有相同的Key时,根据链接时候的先后顺序确定各字典优先级,访问Key时按优先级从高到低访问大字典中的小字典。

比如:

#command_line_args 、 os.environ 、 defaults为三个字典,其中可能存放了相同的Key

combined = ChainMap( command_line_args , os.environ , defaults)

#优先级为command_line_args  os.environ  defaults

访问 combined[Key]时,一定是按command_line_args[Key]、os.environ[Key]、defaults[Key]的先后顺序返回Value。

如果前一个字典没有该Key,就在后一个字典中找,直到找到并返回。如果三个都有,则只返回最前边的。

 

Counter

Counter的本质是字典,记录各个字符出现次数的字典。

from collections import Counter

c=Counter('aababcc')
c
Counter({'a': 3, 'b': 2, 'c': 2})

c[Key]返回,Key值出现的次数

 可以通过Counter的update函数,向Counter中加入新的需要统计的字符。

c.update('Thank you very much!')
c
Counter({' ': 4, 'o': 3, 'y': 3, 'h': 3, 'e': 2, 'l': 2, 'n': 2, 'u': 2, 'H': 1, 'P': 1, 't': 1, 'T': 1, 'a': 1, 'k': 1, 'v': 1, 'r': 1, 'm': 1, 'c': 1, '!': 1})

 

posted @ 2020-10-08 23:07  ShineLe  阅读(69)  评论(0编辑  收藏  举报