Python包之collections

collections提供了特殊的容器类型,可以作为Python内建容器类型的替代选择:

容器类型 说明
namedtuple() 工厂函数,提供创建命名元组子类
deque 类似于list容器,但是支持高效的在容器首尾两端添加和删除元素
Counter 字典的子类,提供对可哈希对象的计数功能
defaultdict 字典的子类,提供工厂函数为字典设置默认值
OrderedDict 字典的子类,有顺序的字典

1.namedtuple()
命名的元组,顾名思义,它为元组的每个位置分配了特殊的含义,有助于编写可读性强、自文档型的代码。命名元组可以应用在任何普通元组能够应用的地方,并且支持通过命名而不是通过位置索引获取元组的元素。
collections.namedtuple(typename, field_names[,verbose=False][,rename=False])
返回一个名为typename的tuple子类A。A可以用于创建类似tuple的对象B,B可以通过名称查找索引数据。
field_names可以是字符串的序列,或者每个field_name以空格或逗号分隔的单个字符串。
有效的Python标识符都可以作为field_names的标识。
如果rename=True,无效的field_names会自动被替换成positional names。例如,['abc', 'def', 'ghi', 'abc']会被替换成 ['abc', '_1', 'ghi', '_3'],其中def为Python的关键字,abc为重复。
如果verbose=True,类在创建之后就被print。

point = namedtuple("point", ["x", "y"])
p = point(11,y=22)  # instantiate with positional or keyword arguments
p
# point(x=11, y=22)
p.x + p.y               # fields also accessible by name
# 33
p[0] + p[1]             # indexable like the plain tuple (11, 22)
# 33
x, y = p                # unpack like a regular tuple
x, y
# (11, 22)

命名元组非常适合用于给CSV模块和sqlite3模块返回的元组赋予field name:

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

import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
    print emp.name, emp.title

命名元组除了继承了元素的方法之外,还支持另外三个方法和一个属性,并且为了便面与field name冲突,方法和属性名称都是以下划线开头:

  • _make(iterable)
    从已有的序列或可迭代对象创建命名元组实例。
point = namedtuple("point", ["x", "y"])
t = [11, 22]
point._make(t)  # 从已有的序列t生成命名元组的实例对象
# point(x=11, y=22)
  • _asdict()
    返回OrderedDict对象,把field names映射到对应的值。
p = point(x=11, y=22)
p._asdict()
# OrderedDict([("x", 11), ("y", 22)])
  • _replace(**kwargs)
    返回新的命名元组实例对象,新的对象把原对象中对应fields的值替换成新值。
p = point(11, 22)
p._replace(x=33)
# point(x=33,y=22)
  • _fields
    返回命名元组的field names的元组。可以用于命名元组的检查和根据已有命名元组创建新的命名元组。
p._fields  # view the field names
# ("x", "y")
Color = namedtuple('Color', 'red green blue')
Pixel = namedtuple('Pixel', Point._fields + Color._fields)
Pixel(11, 22, 128, 255, 0)
# Pixel(x=11, y=22, red=128, green=255, blue=0)

命名元组支持通过getattr()函数获取指定field names的值

getattr(p, "x")   # 11

也可以将字典转成命名元组,通过双星号:

d = {"x":11, "y":22}
point(**d)  # point(x=11, y=22)

命名元组是一个Class,因此可以通过继承的方式创建子类,在子类中可以增加自定义的函数方法。

  1. deque
    class collections.deque([iterable[,maxlen]])
    返回deque对象,以iterable中的data从左到右依次append的方式初始化,如果iterable未指定,则返回空的deque。
    deque,即double-ended queue的简写,是栈和队列的泛化generalization。deque对象支持thread-safe,memory efficient的appends和pops操作,并且支持从头部和尾部分别进行。
    如果maxlen未指定或者为None,deque为无限长度,否则,deque被限定为maxlen指定的长度。如果deque已经达到了最大长度,当有新的元素增加时,会从另外一段删除掉对应数量的元素。
    deque对象支持以下方法:
  • append(x)
    在deque的右端增加元素x。
  • appendleft(x)
    在deque的左端增加元素x。
  • clear()
    清除deque中所有的元素。
  • extend(iterable)
    把iterable中的元素增加到deque的右端。
  • extendleft(iterable)
    把iterable中的元素倒序增加到deque的左端。
  • pop()
    删除并且返回deque对象中最右端的元素。如果deque中没有元素,抛出异常IndexError。
  • popleft()
    删除并且返回deque对象中最左端的元素。如果deque中没有元素,抛出异常IndexError。
  • remove(value)
    从deque中删除第一次出现的value,如果未发现value,抛出异常IndexError。
  • reverse()
    把deque中的元素倒序,并且返回None。
  • retate(n=1)
    把deque向右旋转n次,如果n为负数,则向左旋转。如果deque为非空,deque向右旋转一次相当于把deque中最右端的元素移动到最左端。
    deque对象同时提供了一个只读的属性:maxlen,deque的最大长度,如果未指定则为None。
    3.Counter对象
    Counter工具是用于方便快速地计数。
# Tally occurrences of words in a list
cnt = Counter()
for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
    cnt[word] += 1
cnt
# Counter({'blue': 3, 'red': 2, 'green': 1})

# 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)]

class collections.Counter([iterable-or-mapping])
Counter是字典的子类,用于对可哈希的对象进行计数。Counter是无序的集合,其中元素为字典的key,元素的个数为字典的值,并且元素个数允许为0或者负值。
Counter的元素可以从iterable的对象中计数得到,或者从别的mapping对象初始化得到:

c = Counter()                           # a new, empty counter
c = Counter('gallahad')                 # a new counter from an iterable
c = Counter({'red': 4, 'blue': 2})      # a new counter from a mapping
c = Counter(cats=4, dogs=8)             # a new counter from keyword args

Counter对象具有与字典一样的接口方法,不同的是,对于missing items,Counter对象的值为0,字典会抛出异常keyerror。

c = Counter(['eggs', 'ham'])
c['bacon']                              # count of a missing element is zero
# 0

把Counter对象中的值置为0不会从Counter对象中把元素删除,使用del方法可以删除元素:

c["sausage"] = 0       # counter entry with a zero count
del c['sausage']       # del actually removes the entry

除了字典的方法之外,Counter对象支持额外的三个方法:

  • elements()
    返回一个iterator对象,其元素为Counter中的元素按照计数重复。返回的iterator中元素是无序的。如果Counter中的值小于1,返回的iterator中就不包含该key。
c = Counter(a=4, b=2, c=0, d=-2)
list(c.elements())
# ['a', 'a', 'a', 'a', 'b', 'b']
  • most_common([n])
    返回出现次数最多的n个元素和他们的次数。如果n为None,返回所有元素。出现次数相同的元素的顺序是不确定的。
Counter('abracadabra').most_common(3)
[('a', 5), ('r', 2), ('b', 2)]
  • subtract([iterable-or-mapping])
    从原Counter对象的元素出现的次数减去iterable or mapping or counter对象中元素出现的次数。
c = Counter(a=4, b=2, c=0, d=-2)
d = Counter(a=1, b=2, c=3, d=4)
c.subtract(d)
c
# Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})

字典的方法同样适用于Counter对象,除了以下两个方法有些许差别:

  • fromkeys(iterable)
    Counter对象未实现此类方法。
  • update([iterable-or-mapping])
    iterable oe mapping对象中的元素次数被追加到原Counter对象中。
c = Counter(a=4, b=2, c=0, d=-2)
c.update("abcdabcde")
c
# Counter({'a': 6, 'b': 4, 'c': 2, 'd': 0, 'e': 1})
  1. defaultdict对象
    class collections.defaultdict([default_factory[, ...]])
    defaultdict对象是dict的子类,它重写了一个函数,并且增加了一个可写的实例变量,其他的函数与dict类完全相同。
    第一个参数default_factory为defaultdict对象提供初始值,默认为None,所有其他的参数被传递给dict对象的构造器。
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(list)
for k, v in s:
    d[k].append(v)
d.items()
# [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

defaultdict对象相比dict新增支持的方法:

  • __missing__(key)
    如果default_factory is None,抛出异常KeyError。
    如果default_factory is not None,对于key提供一个默认值。
    defatultdict对象相对dict新增支持的实例变量:
  • default_factory
    该属性被missing方法使用。
    5.orderedDict对象
    orderedDict对象和普通字典一样,除了orderedict能够保持键被插入的顺序。当遍历ordereddict对象时,元素按照键被第一次插入的顺序依次返回。
    class collections.OrderedDict([items])
    orderedDict对象是字典对象的子类,它能够记住元素被插入的顺序。如果key对应的value被更改,保持原有的顺序不便,但是如果删除key然后再插入key,key被移动到最后。
    OrderedDict.popitem(last=True)
    ordereddict对象的popitem方法移除一对(key,value)并且返回该(key,value)。如果last = True,(key,value)被返回的顺序按照LIFO的顺序,否则按照FIFO的顺序。
    除了字典方法外,ordereddict对象另外支持倒序遍历函数reversed()。
    如果要判断两个ordereddict对象相同,必须保证元素类别和顺序均相同。如果判断ordereddict对象和其他mapping对象相同,只需要元素类别相同即可。
# regular unsorted dictionary
d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}

# dictionary sorted by key
OrderedDict(sorted(d.items(), key=lambda t: t[0]))
# OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

# dictionary sorted by value
OrderedDict(sorted(d.items(), key=lambda t: t[1]))
# OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

# dictionary sorted by length of the key string
OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
# OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,009评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,808评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,891评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,283评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,285评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,409评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,809评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,487评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,680评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,499评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,548评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,268评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,815评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,872评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,102评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,683评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,253评论 2 341

推荐阅读更多精彩内容