# `iterutils` - `itertools` 改进¶

`itertools` 中充满了使用Python生成器的很好的例子。然而，仍然存在一些关键差距。 `iterutils` 用功能丰富、经过测试和毕达式的解决方案填补了其中的许多空白。

## 迭代¶

boltons.iterutils.chunked(src, size, count=None, **kw)[源代码]

```>>> chunked(range(10), 3)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
>>> chunked(range(10), 3, fill=None)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, None, None]]
>>> chunked(range(10), 3, count=2)
[[0, 1, 2], [3, 4, 5]]
```

boltons.iterutils.chunked_iter(src, size, **kw)[源代码]

```>>> list(chunked_iter(range(10), 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
>>> list(chunked_iter(range(10), 3, fill=None))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, None, None]]
```

boltons.iterutils.pairwise(src)[源代码]

```>>> pairwise(range(5))
[(0, 1), (1, 2), (2, 3), (3, 4)]
>>> pairwise([])
[]
```

boltons.iterutils.pairwise_iter(src)[源代码]

```>>> list(pairwise_iter(range(5)))
[(0, 1), (1, 2), (2, 3), (3, 4)]
>>> list(pairwise_iter([]))
[]
```

boltons.iterutils.windowed(src, size)[源代码]

boltons.iterutils.windowed_iter(src, size)[源代码]

```>>> list(windowed_iter(range(7), 3))
[(0, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6)]
```

```>>> list(windowed_iter(range(3), 5))
[]
```
boltons.iterutils.unique(src, key=None)[源代码]

`unique()` 返回唯一值的列表，该列表由 key ，按照它们第一次出现在可迭代输入中的顺序， src

```>>> ones_n_zeros = '11010110001010010101010'
>>> ''.join(unique(ones_n_zeros))
'10'
```

boltons.iterutils.unique_iter(src, key=None)[源代码]

```>>> repetitious = [1, 2, 3] * 10
>>> list(unique_iter(repetitious))
[1, 2, 3]
```

```>>> pleasantries = ['hi', 'hello', 'ok', 'bye', 'yes']
>>> list(unique_iter(pleasantries, key=lambda x: len(x)))
['hi', 'hello', 'bye']
```
boltons.iterutils.redundant(src, key=None, groups=False)[源代码]

```>>> redundant([1, 2, 3, 4])
[]
>>> redundant([1, 2, 3, 2, 3, 3, 4])
[2, 3]
>>> redundant([1, 2, 3, 2, 3, 3, 4], groups=True)
[[2, 2], [3, 3, 3]]
```

```>>> redundant(['hi', 'Hi', 'HI', 'hello'], key=str.lower)
['Hi']
>>> redundant(['hi', 'Hi', 'HI', 'hello'], groups=True, key=str.lower)
[['hi', 'Hi', 'HI']]
```

key 中的值时也应使用 src 都不是可控制的。

## 剥离和拆分¶

boltons.iterutils.split(src, sep=None, maxsplit=None)[源代码]

```>>> split(['hi', 'hello', None, None, 'sup', None, 'soap', None])
[['hi', 'hello'], ['sup'], ['soap']]
```

boltons.iterutils.split_iter(src, sep=None, maxsplit=None)[源代码]

• 单一值

• 可迭代的分隔符

• 遇到分隔符时返回True的单参数可调用

`split_iter()` 生成非分隔符值的列表。分隔符永远不会出现在输出中。

```>>> list(split_iter(['hi', 'hello', None, None, 'sup', None, 'soap', None]))
[['hi', 'hello'], ['sup'], ['soap']]
```

Note that `split_iter` is based on `str.split()`, so if sep is `None`, `split()` groups separators. If empty lists are desired between two contiguous `None` values, simply use `sep=[None]`:

```>>> list(split_iter(['hi', 'hello', None, None, 'sup', None]))
[['hi', 'hello'], ['sup']]
>>> list(split_iter(['hi', 'hello', None, None, 'sup', None], sep=[None]))
[['hi', 'hello'], [], ['sup'], []]
```

```>>> falsy_sep = lambda x: not x
>>> list(split_iter(['hi', 'hello', None, '', 'sup', False], falsy_sep))
[['hi', 'hello'], [], ['sup'], []]
```

boltons.iterutils.strip(iterable, strip_value=None)[源代码]

```>>> strip(['Fu', 'Foo', 'Bar', 'Bam', 'Fu'], 'Fu')
['Foo', 'Bar', 'Bam']
```
boltons.iterutils.strip_iter(iterable, strip_value=None)[源代码]

```>>> list(strip_iter(['Fu', 'Foo', 'Bar', 'Bam', 'Fu'], 'Fu'))
['Foo', 'Bar', 'Bam']
```
boltons.iterutils.lstrip(iterable, strip_value=None)[源代码]

```>>> lstrip(['Foo', 'Bar', 'Bam'], 'Foo')
['Bar', 'Bam']
```
boltons.iterutils.lstrip_iter(iterable, strip_value=None)[源代码]

```>>> list(lstrip_iter(['Foo', 'Bar', 'Bam'], 'Foo'))
['Bar', 'Bam']
```
boltons.iterutils.rstrip(iterable, strip_value=None)[源代码]

```>>> rstrip(['Foo', 'Bar', 'Bam'], 'Bam')
['Foo', 'Bar']
```
boltons.iterutils.rstrip_iter(iterable, strip_value=None)[源代码]

```>>> list(rstrip_iter(['Foo', 'Bar', 'Bam'], 'Bam'))
['Foo', 'Bar']
```

## 嵌套式¶

boltons.iterutils.remap(root, visit=<function default_visit>, enter=<function default_enter>, exit=<function default_exit>, **kwargs)[源代码]

Remap(“递归映射”)函数用于遍历和转换嵌套结构。列表、元组、集合和字典只是嵌套到异类树状结构中的几个数据结构，这些结构在编程中非常常见。不幸的是，Python内置的操作集合的方法几乎都是平面的。列表理解可能是快速而简洁的，但它们不会递归，这使得对现实世界的数据应用快速更改或复杂转换变得单调乏味。

```>>> from pprint import pprint
>>> reviews = {'Star Trek': {'TNG': 10, 'DS9': 8.5, 'ENT': None},
...            'Babylon 5': 6, 'Dr. Who': None}
>>> pprint(remap(reviews, lambda p, k, v: v is not None))
{'Babylon 5': 6, 'Star Trek': {'DS9': 8.5, 'TNG': 10}}
```

Remap有四个主要参数：要遍历的对象和决定如何创建重新映射对象的三个可选可调参数。

• root -- 要遍历的目标对象。默认情况下，remap支持可迭代代码，如 `list``tuple``dict` ，及 `set` ，但可以遍历的任何对象 enter 会奏效的。

• visit (callable) -- 中的每一项上都调用此函数 root 。它必须接受三个位置参数， pathkey ，及 valuepath 只是父母密钥的一个元组。 visit 应返回新的键-值对。它也可能会返回 `True` 作为保持旧项不变的速记，或者 `False` 若要从新结构中删除该项，请执行以下操作。 visit 在之后调用 enter ，在新家长身上。这个 visit 函数是为根目录中的每个项调用的，包括重复项。对于可遍历的值，在访问完它的所有子对象之后，在新的父对象上调用它。默认的访问行为只是返回未修改的键-值对。

• enter (callable) -- 此函数用于控制 root 都被遍历了。它接受的参数与 visit ：当前项的路径、键和值。它返回一对空白的新父项，以及一个遍历应该访问的项的迭代器。如果 `False` 而不是迭代器，则不会遍历值。这个 enter 函数在每个唯一值中只调用一次。默认的Enter行为支持映射、序列和集合。不会遍历字符串和所有其他迭代变量。

• exit (callable) -- 此函数确定访问项目后如何处理这些项目。它获得与其他函数相同的三个参数-- pathkeyvalue --再加上两个：从返回的空白新父对象 enter ，以及由重新映射的新项的列表 visit 。喜欢 enter vt.的. exit 函数在每个唯一值中只调用一次。默认的退出行为是简单地将所有新项添加到新的父项，例如，使用 `list.extend()``dict.update()` 要添加到新父项中的。不可变对象，如 `tuple``namedtuple` 必须从头开始重新创建，但使用与从 enter 功能。

• reraise_visit (bool) -- 一种实用的便利 visit 可召回的。当设置为时 `False` ，remap将忽略由 visit 回拨。导致异常的项目将被保留。有关更多详细信息，请参阅示例。

boltons.iterutils.get_path(root, path, default=Sentinel('_UNSET'))[源代码]

```>>> root = {'a': {'b': {'c': [[1], [2], [3]]}}}
>>> get_path(root, ('a', 'b', 'c', 2, 0))
3
```

Get_Path的主要目标之一是改进错误消息传递。EAFP很好，但错误消息不是很好。

• root -- 支持的词典、列表或其他对象的目标嵌套 `__getitem__`

• path (tuple) -- 要在中连续查找的字符串和整数的列表 root

• default -- 要返回的值应为 `PathAccessError` 可以提出例外情况。

boltons.iterutils.research(root, query=<function <lambda>>, reraise=False)[源代码]

```>>> root = {'a': {'b': 1, 'c': (2, 'd', 3)}, 'e': None}
>>> res = research(root, query=lambda p, k, v: isinstance(v, int))
>>> print(sorted(res))
[(('a', 'b'), 1), (('a', 'c', 0), 2), (('a', 'c', 2), 3)]
```

boltons.iterutils.flatten(iterable)[源代码]

`flatten()` 返回来自的所有元素的折叠列表 iterable 同时折叠任何嵌套的可迭代对象。

```>>> nested = [[1, 2], [[3], [4, 5]]]
>>> flatten(nested)
[1, 2, 3, 4, 5]
```
boltons.iterutils.flatten_iter(iterable)[源代码]

`flatten_iter()` 生成来自的所有元素 iterable 同时折叠任何嵌套的可迭代对象。

```>>> nested = [[1, 2], [[3], [4, 5]]]
>>> list(flatten_iter(nested))
[1, 2, 3, 4, 5]
```

## 数字¶

boltons.iterutils.backoff(start, stop, count=None, factor=2.0, jitter=False)[源代码]

```>>> backoff(1, 10)
[1.0, 2.0, 4.0, 8.0, 10.0]
```
boltons.iterutils.backoff_iter(start, stop, count=None, factor=2.0, jitter=False)[源代码]

```>>> list(backoff_iter(1.0, 10.0, count=5))
[1.0, 2.0, 4.0, 8.0, 10.0]
>>> list(backoff_iter(1.0, 10.0, count=8))
[1.0, 2.0, 4.0, 8.0, 10.0, 10.0, 10.0, 10.0]
>>> list(backoff_iter(0.25, 100.0, factor=10))
[0.25, 2.5, 25.0, 100.0]
```

```for timeout in backoff_iter(0.25, 5.0):
try:
res = network_call()
break
except Exception as e:
log(e)
time.sleep(timeout)
```

• start (float) -- 基线为正数。

• stop (float) -- 正数表示最大值。

• count (int) -- 停止迭代前的步骤数。缺省值为 startstop 。传递字符串， 'repeat' ，以无限期地继续迭代。

• factor (float) -- 指数级增长的速度。默认为 2.0 ，例如， [1, 2, 4, 8, 16]

• jitter (float) -- 一个介于两者之间的因素 -1.01.0 ，用于统一随机化，从而在分布式系统中分散超时，从而避免节奏影响。正值使用基本回退曲线作为最大值，负值使用曲线作为最小值。设置为1.0或 True 获得接近以太网久经考验的退避解决方案的抖动。默认为 False

boltons.iterutils.frange(stop, start=None, step=1.0)[源代码]

A `range()` 克隆基于浮点数的范围。

```>>> frange(5)
[0.0, 1.0, 2.0, 3.0, 4.0]
>>> frange(6, step=1.25)
[0.0, 1.25, 2.5, 3.75, 5.0]
>>> frange(100.5, 101.5, 0.25)
[100.5, 100.75, 101.0, 101.25]
>>> frange(5, 0)
[]
>>> frange(5, 0, step=-1.25)
[5.0, 3.75, 2.5, 1.25]
```
boltons.iterutils.xfrange(stop, start=None, step=1.0)[源代码]

```>>> tuple(xfrange(1, 3, step=0.75))
(1.0, 1.75, 2.5)
```

## 分类¶

boltons.iterutils.bucketize(src, key=<class 'bool'>, value_transform=None, key_filter=None)[源代码]

```>>> bucketize(range(5))
{False: [0], True: [1, 2, 3, 4]}
>>> is_odd = lambda x: x % 2 == 1
>>> bucketize(range(5), is_odd)
{False: [0, 2, 4], True: [1, 3]}
```

key`bool` 默认情况下，它可以是可调用的，也可以是字符串或列表(如果它是字符串)，它是要对对象进行分段化的属性的名称。

```>>> bucketize([1+1j, 2+2j, 1, 2], key='real')
{1.0: [(1+1j), 1], 2.0: [(2+2j), 2]}
```

```>>> bucketize([1,2,365,4,98],key=[0,1,2,0,2])
{0: [1, 4], 1: [2], 2: [365, 98]}
```

```>>> bucketize([None, None, None, 'hello'])
{False: [None, None, None], True: ['hello']}
```

```>>> bucketize(range(10), lambda x: x % 3)
{0: [0, 3, 6, 9], 1: [1, 4, 7], 2: [2, 5, 8]}
```

`bucketize` 有几个高级选项在某些情况下很有用。 value_transform 可用于在将值添加到存储桶时修改值，以及 key_filter 将允许将某些存储桶排除在收集之外。

```>>> bucketize(range(5), value_transform=lambda x: x*x)
{False: [0], True: [1, 4, 9, 16]}
```
```>>> bucketize(range(10), key=lambda x: x % 3, key_filter=lambda k: k % 3 != 1)
{0: [0, 3, 6, 9], 2: [2, 5, 8]}
```

boltons.iterutils.partition(src, key=<class 'bool'>)[源代码]

```>>> nonempty, empty = partition(['', '', 'hi', '', 'bye'])
>>> nonempty
['hi', 'bye']
```

key 默认为 `bool` ，但可以小心地重写，以使用返回以下两个函数之一的函数 `True``False` 或要对其进行对象分区的属性的字符串名称。

```>>> import string
>>> is_digit = lambda x: x in string.digits
>>> decimal_digits, hexletters = partition(string.hexdigits, is_digit)
>>> ''.join(decimal_digits), ''.join(hexletters)
('0123456789', 'abcdefABCDEF')
```

## 分选¶

boltons.iterutils.soft_sorted(iterable, first=None, last=None, key=None, reverse=False)[源代码]

```>>> soft_sorted(['two', 'b', 'one', 'a'], first=['one', 'two'])
['one', 'two', 'a', 'b']
>>> soft_sorted(range(7), first=[6, 15], last=[2, 4], reverse=True)
[6, 5, 3, 1, 0, 2, 4]
>>> import string
>>> ''.join(soft_sorted(string.hexdigits, first='za1', last='b', key=str.lower))
'aA1023456789cCdDeEfFbB'
```

• iterable (list) -- 列表或其他可迭代排序的列表。

• first (list) -- 对应该出现在返回列表开头的元素强制执行的序列。

• last (list) -- 对应出现在返回列表末尾的元素强制执行的序列。

• key (callable) -- Callable用于为每个要排序的项生成一个类似的键，与 `sorted()` 。请注意，中的条目 firstlast 应该是这些物品的钥匙。默认为通过/身份功能。

• reverse (bool) -- 无论元素是否未显式排序 firstlast 是否应该按相反的顺序排列。

boltons.iterutils.untyped_sorted(iterable, key=None, reverse=False)[源代码]

```>>> untyped_sorted(['abc', 2.0, 1, 2, 'def'])
[1, 2.0, 2, 'abc', 'def']
```

## 减少¶

`reduce()` 是一个强大的功能，但它也是非常开放的，并不总是最具可读性的。标准库认识到这一点，添加了 `sum()``all()` ，及 `any()` 。所有这些函数都需要一个基本运算符 (`+``and` ，及 `or` )，并使用运算符将可迭代变量转换为单个值。

boltons.iterutils.one(src, default=None, key=None)[源代码]

```>>> one((True, False, False))
True
>>> one((True, False, True))
>>> one((0, 0, 'a'))
'a'
>>> one((0, False, None))
>>> one((True, True), default=False)
False
>>> bool(one(('', 1)))
True
>>> one((10, 20, 30, 42), key=lambda i: i > 40)
42
```

boltons.iterutils.first(iterable, default=None, key=None)[源代码]

```>>> first([0, False, None, [], (), 42])
42
>>> first([0, False, None, [], ()]) is None
True
>>> first([0, False, None, [], ()], default='ohai')
'ohai'
>>> import re
>>> m = first(re.match(regex, 'abc') for regex in ['b.*', 'a(.*)'])
>>> m.group(1)
'bc'
```

```>>> first([1, 1, 3, 4, 5], key=lambda x: x % 2 == 0)
4
```

boltons.iterutils.same(iterable, ref=Sentinel('_UNSET'))[源代码]

`same()` 退货 `True` 当中的所有值 iterable 彼此相等，或者可选地为参考值， ref 。类似于 `all()``any()` 因为它计算一个可迭代数并返回一个 `bool``same()` 退货 `True` 用于空的可迭代对象。

```>>> same([])
True
>>> same([1])
True
>>> same(['a', 'a', 'a'])
True
>>> same(range(20))
False
>>> same([[], []])
True
>>> same([[], []], ref='test')
False
```

## 类型检查¶

boltons.iterutils.is_iterable(obj)[源代码]

```>>> is_iterable([])
True
>>> is_iterable(object())
False
```
boltons.iterutils.is_scalar(obj)[源代码]

```>>> is_scalar(object())
True
>>> is_scalar(range(10))
False
>>> is_scalar('hello')
True
```
boltons.iterutils.is_collection(obj)[源代码]

```>>> is_collection(object())
False
>>> is_collection(range(10))
True
>>> is_collection('hello')
False
```