创新互联Python教程:collections—-容器数据类型

collections —- 容器数据类型

Source code:Lib/collections/__init__.py


这个模块实现了特定目标的容器,以提供python标准内建容器 dict , list , set , 和 tuple 的替代选择。

namedtuple()

创建命名元组子类的工厂函数

deque

类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop)

ChainMap

类似字典(dict)的容器类,将多个映射集合到一个视图里面

Counter

字典的子类,提供了可哈希对象的计数功能

OrderedDict

字典的子类,保存了他们被添加的顺序

defaultdict

字典的子类,提供了一个工厂函数,为字典查询提供一个默认值

UserDict

封装了字典对象,简化了字典子类化

UserList

封装了列表对象,简化了列表子类化

UserString

封装了字符串对象,简化了字符串子类化

ChainMap 对象

3.3 新版功能.

一个 ChainMap 类是为了将多个映射快速的链接到一起,这样它们就可以作为一个单元处理。它通常比创建一个新字典和多次调用 update() 要快很多。

这个类可以用于模拟嵌套作用域,并且在模版化的时候比较有用。

class collections.ChainMap(\maps*)

一个 ChainMap 将多个字典或者其他映射组合在一起,创建一个单独的可更新的视图。 如果没有 maps 被指定,就提供一个默认的空字典,这样一个新链至少有一个映射。

底层映射被存储在一个列表中。这个列表是公开的,可以通过 maps 属性存取和更新。没有其他的状态。

搜索查询底层映射,直到一个键被找到。不同的是,写,更新和删除只操作第一个映射。

一个 ChainMap 通过引用合并底层映射。 所以,如果一个底层映射更新了,这些更改会反映到 ChainMap 。

支持所有常用字典方法。另外还有一个 maps 属性(attribute),一个创建子上下文的方法(method), 一个存取它们首个映射的属性(property):

  • maps

    一个可以更新的映射列表。这个列表是按照第一次搜索到最后一次搜索的顺序组织的。它是仅有的存储状态,可以被修改。列表最少包含一个映射。

  • new_child(m=None, \*kwargs*)

    返回一个新的 ChainMap,其中包含一个新的映射,后面跟随当前实例中的所有映射。 如果指定了 m,它会成为新的映射加在映射列表的前面;如果未指定,则会使用一个空字典,因此调用 d.new_child() 就等价于 ChainMap({}, *d.maps)。 如果指定了任何关键字参数,它们会更新所传入的映射或新的空字典。 此方法被用于创建子上下文,它可在不改变任何上级映射的情况下被更新。

    在 3.4 版更改: 添加了 m 可选参数。

    在 3.10 版更改: 增加了对关键字参数的支持。

  • parents

    属性返回一个新的 ChainMap 包含所有的当前实例的映射,除了第一个。这样可以在搜索的时候跳过第一个映射。 使用的场景类似在 nested scopes 嵌套作用域中使用 nonlocal 关键词。用例也可以类比内建函数 super() 。一个 d.parents 的引用等价于 ChainMap(*d.maps[1:])

注意,一个 ChainMap() 的迭代顺序是通过从后往前扫描所有映射来确定的:

 
 
 
 
  1. >>> baseline = {'music': 'bach', 'art': 'rembrandt'}
  2. >>> adjustments = {'art': 'van gogh', 'opera': 'carmen'}
  3. >>> list(ChainMap(adjustments, baseline))
  4. ['music', 'art', 'opera']

这给出了与 dict.update() 调用序列相同的顺序,从最后一个映射开始:

 
 
 
 
  1. >>> combined = baseline.copy()
  2. >>> combined.update(adjustments)
  3. >>> list(combined)
  4. ['music', 'art', 'opera']

在 3.9 版更改: 增加了对 ||= 运算符的支持,相关说明见 PEP 584。

参见

  • MultiContext class 在 Enthought CodeTools package 有支持写映射的选项。

  • Django 中用于模板的 Context class 是只读的映射链。 它还具有上下文推送和弹出特性,类似于 new_child() 方法和 parents 特征属性。

  • Nested Contexts recipe 提供了是否对第一个映射或其他映射进行写和其他修改的选项。

  • 一个 极简的只读版 Chainmap.

ChainMap 例子和方法

这一节提供了多个使用链映射的案例。

模拟Python内部lookup链的例子

 
 
 
 
  1. import builtins
  2. pylookup = ChainMap(locals(), globals(), vars(builtins))

让用户指定的命令行参数优先于环境变量,优先于默认值的例子

 
 
 
 
  1. import os, argparse
  2. defaults = {'color': 'red', 'user': 'guest'}
  3. parser = argparse.ArgumentParser()
  4. parser.add_argument('-u', '--user')
  5. parser.add_argument('-c', '--color')
  6. namespace = parser.parse_args()
  7. command_line_args = {k: v for k, v in vars(namespace).items() if v is not None}
  8. combined = ChainMap(command_line_args, os.environ, defaults)
  9. print(combined['color'])
  10. print(combined['user'])

用 ChainMap 类模拟嵌套上下文的例子

 
 
 
 
  1. c = ChainMap() # Create root context
  2. d = c.new_child() # Create nested child context
  3. e = c.new_child() # Child of c, independent from d
  4. e.maps[0] # Current context dictionary -- like Python's locals()
  5. e.maps[-1] # Root context -- like Python's globals()
  6. e.parents # Enclosing context chain -- like Python's nonlocals
  7. d['x'] = 1 # Set value in current context
  8. d['x'] # Get first key in the chain of contexts
  9. del d['x'] # Delete from current context
  10. list(d) # All nested values
  11. k in d # Check all nested values
  12. len(d) # Number of nested values
  13. d.items() # All nested items
  14. dict(d) # Flatten into a regular dictionary

ChainMap 类只更新链中的第一个映射,但lookup会搜索整个链。 然而,如果需要深度写和删除,也可以很容易的通过定义一个子类来实现它

 
 
 
 
  1. class DeepChainMap(ChainMap):
  2. 'Variant of ChainMap that allows direct updates to inner scopes'
  3. def __setitem__(self, key, value):
  4. for mapping in self.maps:
  5. if key in mapping:
  6. mapping[key] = value
  7. return
  8. self.maps[0][key] = value
  9. def __delitem__(self, key):
  10. for mapping in self.maps:
  11. if key in mapping:
  12. del mapping[key]
  13. return
  14. raise KeyError(key)
  15. >>> d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})
  16. >>> d['lion'] = 'orange' # update an existing key two levels down
  17. >>> d['snake'] = 'red' # new keys get added to the topmost dict
  18. >>> del d['elephant'] # remove an existing key one level down
  19. >>> d # display result
  20. DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})

Counter 对象

一个计数器工具提供快速和方便的计数。比如

 
 
 
 
  1. >>> # Tally occurrences of words in a list
  2. >>> cnt = Counter()
  3. >>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
  4. ... cnt[word] += 1
  5. >>> cnt
  6. Counter({'blue': 3, 'red': 2, 'green': 1})
  7. >>> # Find the ten most common words in Hamlet
  8. >>> import re
  9. >>> words = re.findall(r'\w+', open('hamlet.txt').read().lower())
  10. >>> Counter(words).most_common(10)
  11. [('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),
  12. ('you', 554), ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]

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

一个 Counter 是一个 dict 的子类,用于计数可哈希对象。它是一个集合,元素像字典键(key)一样存储,它们的计数存储为值。计数可以是任何整数值,包括0和负数。 Counter 类有点像其他语言中的 bags或multisets。

元素从一个 iterable 被计数或从其他的 mapping (or counter)初始化:

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

Counter对象有一个字典接口,如果引用的键没有任何记录,就返回一个0,而不是弹出一个 KeyError :

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

设置一个计数为0不会从计数器中移去一个元素。使用 del 来删除它:

 
 
 
 
  1. >>> c['sausage'] = 0 # counter entry with a zero count
  2. >>> del c['sausage'] # del actually removes the entry

3.1 新版功能.

在 3.7 版更改: 作为 dict 的子类,Counter 继承了记住插入顺序的功能。 在 Counter 对象上的许多操作也会保持顺序。 结果会先按元素在运算符左边首次出现的时间排序再按其在运算符右边的出现时间排序。

Counter 对象在对所有字典可用的方法以外还支持一些附加方法:

  • elements()

    返回一个迭代器,其中每个元素将重复出现计数值所指定次。 元素会按首次出现的顺序返回。 如果一个元素的计数值小于一,elements() 将会忽略它。

       
       
       
       
    1. >>> c = Counter(a=4, b=2, c=0, d=-2)
    2. >>> sorted(c.elements())
    3. ['a', 'a', 'a', 'a', 'b', 'b']
  • most_common([n])

    返回一个列表,其中包含 n 个最常见的元素及出现次数,按常见程度由高到低排序。 如果 n 被省略或为 None,most_common() 将返回计数器中的 所有 元素。 计数值相等的元素按首次出现的顺序排序:

       
       
       
       
    1. >>> Counter('abracadabra').most_common(3)
    2. [('a', 5), ('b', 2), ('r', 2)]
  • subtract([iterable-or-mapping])

    迭代对象映射对象 减去元素。像 dict.update() 但是是减去,而不是替换。输入和输出都可以是0或者负数。

       
       
       
       
    1. >>> c = Counter(a=4, b=2, c=0, d=-2)
    2. >>> d = Counter(a=1, b=2, c=3, d=4)
    3. >>> c.subtract(d)
    4. >>> c
    5. Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})

    3.2 新版功能.

  • total()

    计算总计数值。

       
       
       
       
    1. >>> c = Counter(a=10, b=5, c=0)
    2. >>> c.total()
    3. 15

    3.10 新版功能.

通常字典方法都可用于 Counter 对象,除了有两个方法工作方式与字典并不相同。

  • fromkeys(iterable)

    这个类方法没有在 Counter 中实现。

  • update([iterable-or-mapping])

    迭代对象 计数元素或者 从另一个 映射对象 (或计数器) 添加。 像 dict.update() 但是是加上,而不是替换。另外,迭代对象 应该是序列元素,而不是一个 (key, value) 对。

计数对象支持相等性、子集和超集关系等富比较运算符: ==, !=, <, <=, >, >=。 所有这些检测会将不存在的元素当作计数值为零,因此 Counter(a=1) == Counter(a=1, b=0) 将返回真值。

3.10 新版功能: 增加了富比较运算。

在 3.10 版更改: 在相等性检测中,不存在的元素会被当作计数值为零。 在此之前,Counter(a=3)Counter(a=3, b=0) 会被视为不同。

Counter 对象的常用案例

 
 
 
 
  1. c.total() # total of all counts
  2. c.clear() # reset all counts
  3. list(c) # list unique elements
  4. set(c) # convert to a set
  5. dict(c) # convert to a regular dictionary
  6. c.items() # convert to a list of (elem, cnt) pairs
  7. Counter(dict(list_of_pairs)) # convert from a list of (elem, cnt) pairs
  8. c.most_common()[:-n-1:-1] # n least common elements
  9. +c # remove zero and negative counts

提供了几种数学运算用来合并 Counter 对象以产生多重集(计数值大于零的计数器)。 加法和减法运算是通过增加或减少相应元素的计数值来合并计数器。 交集和并集运算是返回相应计数的最小值和最大值。 相等和包括运算是对相应计数进行比较。 每种运算都可接受带符号计数的输入,但输出将排除计数为零或小于零的结果。

 
 
 
 
  1. >>> c = Counter(a=3, b=1)
  2. >>> d = Counter(a=1, b=2)
  3. >>> c + d # add two counters together: c[x] + d[x]
  4. Counter({'a': 4, 'b': 3})
  5. >>> c - d # subtract (keeping only positive counts)
  6. Counter({'a': 2})
  7. >>> c & d # intersection: min(c[x], d[x])
  8. Counter({'a': 1, 'b': 1})
  9. >>> c | d # union: max(c[x], d[x])
  10. Counter({'a': 3, 'b': 2})
  11. >>> c == d # equality: c[x] == d[x]
  12. False
  13. >>> c <= d # inclusion: c[x] <= d[x]
  14. False

单目加和减(一元操作符)意思是从空计数器加或者减去。

 
 
 
 
  1. >>> c = Counter(a=2, b=-4)
  2. >>> +c
  3. Counter({'a': 2})
  4. >>> -c
  5. Counter({'b': 4})

3.3 新版功能: 添加了对一元加,一元减和位置集合操作的支持。

备注

计数器主要是为了表达运行的正的计数而设计;但是,小心不要预先排除负数或者其他类型。为了帮助这些用例,这一节记录了最小范围和类型限制。

  • Counter 类是一个字典的子类,不限制键和值。值用于表示计数,但你实际上 可以 存储任何其他值。

  • most_common() 方法在值需要排序的时候用。

  • 原地操作比如 c[key] += 1 , 值类型只需要支持加和减。 所以分数,小数,和十进制都可以用,负值也可以支持。这两个方法 update() 和 subtract() 的输入和输出也一样支持负数和0。

  • Multiset多集合方法只为正值的使用情况设计。输入可以是负数或者0,但只输出计数为正的值。没有类型限制,但值类型需要支持加,减和比较操作。

  • elements() 方法要求正整数计数。忽略0和负数计数。

参见

  • Bag class 在 Smalltalk。

  • Wikipedia 链接 Multisets.

  • C++ multisets 教程和例子。

  • 数学操作和多集合用例,参考 Knuth, Donald. The Art of Computer Programming Volume II, Section 4.6.3, Exercise 19

  • 在给定数量和集合元素枚举所有不同的多集合,参考 itertools.combinations_with_replacement()

       
       
       
       
    1. map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC

deque 对象

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

返回一个新的双向队列对象,从左到右初始化(用方法 append()) ,从 iterable (迭代对象) 数据创建。如果 iterable 没有指定,新队列为空。

Deque队列是由栈或者queue队列生成的(发音是 “deck”,”double-ended queue”的简称)。Deque 支持线程安全,内存高效添加(append)和弹出(pop),从两端都可以,两个方向的大概开销都是 O(1) 复杂度。

虽然 list 对象也支持类似操作,不过这里优化了定长操作和 pop(0)insert(0, v) 的开销。它们引起 O(n) 内存移动的操作,改变底层数据表达的大小和位置。

如果 maxlen 没有指定或者是 None ,deques 可以增长到任意长度。否则,deque就限定到指定最大长度。一旦限定长度的deque满了,当新项加入时,同样数量的项就从另一端弹出。限定长度deque提供类似Unix filter tail 的功能。它们同样可以用与追踪最近的交换和其他数据池活动。

双向队列(deque)对象支持以下方法:

  • append(x)

    添加 x 到右端。

  • appendleft(x)

    添加 x 到左端。

  • clear()

    移除所有元素,使其长度为0.

  • copy()

    创建一份浅拷贝。

    3.5 新版功能.

  • count(x)

    计算 deque 中元素等于 x 的个数。

    3.2 新版功能.

  • extend(iterable)

    扩展deque的右侧,通过添加iterable参数中的元素。

  • extendleft(iterable)

    扩展deque的左侧,通过添加iterable参数中的元素。注意,左添加时,在结果中iterable参数中的顺序将被反过来添加。

  • index(x[, start[, stop]])

    返回 x 在 deque 中的位置(在索引 start 之后,索引 stop 之前)。 返回第一个匹配项,如果未找到则引发 ValueError。

    3.5 新版功能.

  • insert(i, x)

    在位置 i 插入 x

    如果插入会导致一个限长 deque 超出长度 maxlen 的话,就引发一个 IndexError。

    3.5 新版功能.

  • pop()

    移去并且返回一个元素,deque 最右侧的那一个。 如果没有元素的话,就引发一个 IndexError。

  • popleft()

    移去并且返回一个元素,deque 最左侧的那一个。 如果没有元素的话,就引发 IndexError。

  • remove(value)

    移除找到的第一个 value。 如果没有的话就引发 ValueError。

  • reverse()

    将deque逆序排列。返回 None

    3.2 新版功能.

  • rotate(n=1)

    向右循环移动 n 步。 如果 n 是负数,就向左循环。

    如果deque不是空的,向右循环移动一步就等价于 d.appendleft(d.pop()) , 向左循环一步就等价于 d.append(d.popleft())

Deque对象同样提供了一个只读属性:

  • maxlen

    Deque的最大尺寸,如果没有限定的话就是 None

    3.1 新版功能.

除了以上操作,deque 还支持迭代、封存、len(d)reversed(d)copy.copy(d)copy.deepcopy(d)、成员检测运算符 in 以及下标引用例如通过 d[0] 访问首个元素等。 索引访问在两端的复杂度均为 O(1) 但在中间则会低至 O(n)。 如需快速随机访问,请改用列表。

Deque从版本3.5开始支持 __add__(), __mul__(), 和 __imul__()

示例:

 
 
 
 
  1. >>> from collections import deque
  2. >>> d = deque('ghi') # make a new deque with three items
  3. >>> for elem in d: # iterate over the deque's elements
  4. ... print(elem.upper())
  5. G
  6. H
  7. I
  8. >>> d.append('j') # add a new entry to the right side
  9. >>> d.appendleft('f') # add a new entry to the left side
  10. >>> d # show the representation of the deque
  11. deque(['f', 'g', 'h', 'i', 'j'])
  12. >>> d.pop() # return and remove the rightmost item
  13. 'j'
  14. >>> d.popleft() # return and remove the leftmost item
  15. 'f'
  16. >>> list(d) # list the contents of the deque
  17. ['g', 'h', 'i']
  18. >>> d[0] # peek at leftmost item
  19. 'g'
  20. >>> d[-1] # peek at rightmost item
  21. 'i'
  22. >>> list(reversed(d)) # list the contents of a deque in reverse
  23. ['i', 'h', 'g']
  24. >>> 'h' in d # search the deque
  25. True
  26. >>> d.extend('jkl') # add multiple elements at once
  27. >>> d
  28. deque(['g', 'h', 'i', 'j', 'k', 'l'])
  29. >>> d.rotate(1) # right rotation
  30. >>> d
  31. deque(['l', 'g', 'h', 'i', 'j', 'k'])
  32. >>> d.rotate(-1) # left rotation
  33. >>> d
  34. deque(['g', 'h', 'i', 'j', 'k', 'l'])
  35. >>> deque(reversed(d)) # make a new deque in reverse order
  36. deque(['l', 'k', 'j', 'i', 'h', 'g'])
  37. >>> d.clear() # empty the deque
  38. >>> d.pop() # cannot pop from an empty deque
  39. Traceback (most recent call last):
  40. File "", line 1, in -toplevel-
  41. d.pop()
  42. IndexError: pop from an empty deque
  43. >>> d.extendleft('abc') # extendleft() reverses the input order
  44. >>> d
  45. deque(['c', 'b', 'a'])

deque 用法

这一节展示了deque的多种用法。

限长deque提供了类似Unix tail 过滤功能

 
 
 
 
  1. def tail(filename, n=10):
  2. 'Return the last n lines of a file'
  3. with open(filename) as f:
  4. return deque(f, n)

另一个用法是维护一个近期添加元素的序列,通过从右边添加和从左边弹出

 
 
 
 
  1. def moving_average(iterable, n=3):
  2. # moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
  3. # https://en.wikipedia.org/wiki/Moving_average
  4. it = iter(iterable)
  5. d = deque(itertools.islice(it, n-1))
  6. d.appendleft(0)
  7. s = sum(d)
  8. for elem in it:
  9. s += elem - d.popleft()
  10. d.append(elem)
  11. yield s / n

一个 轮询调度器 可以通过在 deque 中放入迭代器来实现。值从当前迭代器的位置0被取出并暂存(yield)。 如果这个迭代器消耗完毕,就用 popleft() 将其从对列中移去;否则,就通过 rotate() 将它移到队列的末尾

 
 
 
 
  1. def roundrobin(*iterables):
  2. "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
  3. iterators = deque(map(iter, iterables))
  4. while iterators:
  5. try:
  6. while True:
  7. yield next(iterators[0])
  8. iterators.rotate(-1)
  9. except StopIteration:
  10. # Remove an exhausted iterator.
  11. iterators.popleft()

rotate() 方法提供了一种方式来实现 deque 切片和删除。 例如, 一个纯的Python del d[n] 实现依赖于 rotate() 来定位要弹出的元素

 
 
 
 
  1. def delete_nth(d, n):
  2. d.rotate(-n)
  3. d.popleft()
  4. d.rotate(n)

要实现 deque 切片, 使用一个类似的方法,应用 rotate() 将目标元素放到左边。通过 popleft() 移去老的条目(entries),通过 extend() 添加新的条目, 然后反向 rotate。这个方法可以最小代价实现命令式的栈操作,诸如 dup, drop, swap, over, pick, rot, 和 roll

defaultdict 对象

class collections.defaultdict(default_factory=None, /[, ])

返回一个新的类似字典的对象。 defaultdict 是内置 dict 类的子类。 它重载了一个方法并添加了一个可写的实例变量。 其余的功能与 dict 类相同因而不在此文档中写明。

本对象包含一个名为 default_factory 的属性,构造时,第一个参数用于为该属性提供初始值,默认为 None。所有其他参数(包括关键字参数)都相当于传递给 dict 的构造函数。

defaultdict 对象除了支持标准 dict 的操作,还支持以下方法作为扩展:

  • __missing__(key)

    如果 default_factory 属性为 None,则调用本方法会抛出 KeyError 异常,附带参数 key

    如果 default_factory 不为 None,则它会被(不带参数地)调用来为 key 提供一个默认值,这个值和 key 作为一对键值对被插入到字典中,并作为本方法的返回值返回。

    如果调用 default_factory 时抛出了异常,这个异常会原封不动地向外层传递。

    在无法找到所需键值时,本方法会被 dict 中的 __getitem__() 方法调用。无论本方法返回了值还是抛出了异常,都会被 __getitem__() 传递。

    注意,__missing__() 不会__getitem__() 以外的其他方法调用。意味着 get() 会像正常的 dict 那样返回 None,而不是使用 default_factory。

defaultdict 对象支持以下实例变量:

  • default_factory

    本属性由 __missing__() 方法来调用。如果构造对象时提供了第一个参数,则本属性会被初始化成那个参数,如果未提供第一个参数,则本属性为 None

在 3.9 版更改: 增加了合并 (|) 与更新 (|=) 运算符,相关说明见 PEP 584。

defaultdict 例子

使用 list 作为 default_factory,很轻松地将(键-值对组成的)序列转换为(键-列表组成的)字典:

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

当每个键第一次遇见时,它还没有在字典里面,所以自动创建该条目,即调用 default_factory 方法,返回一个空的 list。 list.append() 操作添加值到这个新的列表里。当再次存取该键时,就正常操作,list.append() 添加另一个值到列表中。这个计数比它的等价方法 dict.setdefault() 要快速和简单:

 
 
 
 
  1. >>> d = {}
  2. >>> for k, v in s:
  3. ... d.setdefault(k, []).append(v)
  4. ...
  5. >>> sorted(d.items())
  6. [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

设置 default_factory 为 int,使 defaultdict 用于计数(类似其他语言中的 bag 或 multiset):

 
 
 
 
  1. >>> s = 'mississippi'
  2. >>> d = defaultdict(int)
  3. >>> for k in s:
  4. ... d[k] += 1
  5. ...
  6. >>> sorted(d.items())
  7. [('i', 4), ('m', 1), ('p', 2), ('s', 4)]

当一个字母首次遇到时,它会查询失败,则 default_factory 会调用 int() 来提供一个整数 0 作为默认值。后续的自增操作建立起对每个字母的计数。

函数 int() 总是返回 0,这是常数函数的特殊情况。一个更快和灵活的方法是使用 lambda 函数,可以提供任何常量值(不只是0):

 
 
 
 
  1. >>> def constant_factory(value):
  2. ... return lambda: value
  3. >>> d = defaultdict(constant_factory(''))
  4. >>> d.update(name='John', action='ran')
  5. >>> '%(name)s %(action)s to %(object)s' % d
  6. 'John ran to '

设置 default_factory 为 set 使 defaultdict 用于构建 set 集合:

 
 
 
 
  1. >>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
  2. >>> d = defaultdict(set)
  3. >>> for k, v in s:
  4. ... d[k].add(v)
  5. ...
  6. >>> sorted(d.items())
  7. [('blue', {2, 4}), ('red', {1, 3})]

namedtuple() 命名元组的工厂函数

命名元组赋予每个位置一个含义,提供可读性和自文档性。它们可以用于任何普通元组,并添加了通过名字获取值的能力,通过索引值也是可以的。

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

返回一个新的元组子类,名为 typename 。这个新的子类用于创建类元组的对象,可以通过字段名来获取属性值,同样也可以通过索引和迭代获取值。子类实例同样有文档字符串(类名和字段名)另外一个有用的 __repr__() 方法,以 name=value 格式列明了元组内容。

field_names 是一个像 [‘x’, ‘y’] 一样的字符串序列。另外 field_names 可以是一个纯字符串,用空白或逗号分隔开元素名,比如 'x y' 或者 'x, y'

任何有效的Python 标识符都可以作为字段名,除了下划线开头的那些。有效标识符由字母,数字,下划线组成,但首字母不能是数字或下划线,另外不能是关键词 keyword 比如 class, for, return, global, pass, 或 raise

如果 rename 为真, 无效字段名会自动转换成位置名。比如 ['abc', 'def', 'ghi', 'abc'] 转换成 ['abc', '_1', 'ghi', '_3'] , 消除关键词 def 和重复字段名 abc

defaults 可以为 None 或者是一个默认值的 iterable 。如果一个默认值域必须跟其他没有默认值的域在一起出现,defaults 就应用到最右边的参数。比如如果域名 ['x', 'y', 'z'] 和默认值 (1, 2) ,那么 x 就必须指定一个参数值 ,y 默认值 1z 默认值 2

如果 module 值有定义,命名元组的 __module__ 属性值就被设置。

命名元组实例没有字典,所以它们要更轻量,并且占用更小内存。

要支持封存操作,应当将命名元组类赋值给一个匹配 typename 的变量。

在 3.1 版更改: 添加了对 rename 的支持。

在 3.6 版更改: verboserename 参数成为 仅限关键字参数.

在 3.6 版更改: 添加了 module 参数。

在 3.7 版更改: 移除了 verbose 形参和 _source 属性。

在 3.7 版更改: 添加了 defaults 参数和 _field_defaults 属性。

 
 
 
 
  1. >>> # Basic example
  2. >>> Point = namedtuple('

    文章标题:创新互联Python教程:collections—-容器数据类型
    标题链接:http://www.shufengxianlan.com/qtweb/news34/463334.html

    网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联