excel中函数的使用:使用 itertools 模块中的组合函数

  Python 2.2 对 Python 语言引入了简单生成器并根据底层迭代器重新构思了标准循环在 Python 2.3 中生成器成了标准(不需要 _future_)而且引入了新模块 itertools 以和迭代器起灵活地工作itertools 模块本质上是组组合高阶只不过这些和惰性迭代器起工作而不是和有限列表起工作在这篇专栏文章中David 研究了该新模块并使您感受下组合迭代器所具有富有表现力强大新功能

  理解新概念

  Python V2.2 中引入了迭代器思想这并不十分正确;这种思想“苗头”早已出现在较老 xrange 以及文件思路方法 .xreadlines 中了通过引入 yield 关键字Python 2.2 在内部实现许多方面推广了这概念并使编程定制迭代器变得更为简单( yield 出现使转换成生成器而生成器反过来又返回迭代器)

  迭代器背后动机有两方面将数据作为序列处理通常是最简单思路方法而以线性顺序处理序列通常并不需要都同时实际 存在

  x* 前兆提供了这些原理清晰举例如果您想对某操作执行成千上万次那么执行您可能要花些时间但该般不需要占用大量内存同样对于许多类型文件可以行地处理且不需要将整个文件存储在内存中最好对其它所有种类序列也进行惰性处理;它们可能依赖于通过通道逐步到达数据或者依赖于步执行计算

  大多数时候迭代器用在 for 循环内就象真正序列那样迭代器提供了 .next 思路方法它可以被显式但有百分的 9十 9可能您所看到是以下行:

for x in iterator:
  do_something_with(x)


  在对 iterator.next 进行幕后而产生 StopIteration 异常时该循环就被终止顺便说通过 iter(seq) 实际序列可以被转换成迭代器 - 这不会节省任何内存但是在下面讨论中它会很有用

  Python 不断发展分裂性格

  Python 对编程(FP)观点有点相互矛盾方面许多 Python 开发人员轻视传统 FP map 、 filter 和 reduce 常常建议使用“列表理解”来代替它们但完整 itertools 模块恰恰是由和这些类型完全相同组成只不过这些对“惰性序列”(迭代器)操作而不是对完整序列(列表元组)操作而且Python 2.3 中没有任何“迭代器理解”语法这似乎和列表理解拥有动机

  我猜想 Python 最终会产生某种形式迭代器理解但这取决于找到合适于它们自然语法同时在 itertools 模块中我们拥有大量有用组合大致地这些个都接受些参数(通常包含些基础迭代器)并返回个新迭代器例如 ilter 、 imap 和 izip 都分别直接等同于缺少词首 i 内置

  缺少等价

  itertools 中没有 ireduce 尽管按道理很自然地应该有这个;可能 Python 实现是:

  清单 1. ireduce 样本实现

def ireduce(func, iterable, init=None):
   init is None:
    iterable = iter(iterable)
    curr = iterable.next
  :
    curr = init
  for x in iterable:
    curr = func(curr, x)
    yield curr


  ireduce 用例类似于 reduce 用例例如假设您想要添加某个大型文件所包含列数字但是当满足个条件时就停止您可以使用以下代码来监控正在计算合计数:

  清单 2. 添加并合计列数

from operator import add
from itertools import *
nums = open('numbers')
for tot in takewhile(condition, ireduce(add, imap(, nums)):
  pr "total =", tot


  个更实际举例可能类似于将事件流应用于有状态对象上例如应用到 GUI 窗口小部件上但是即使是上述简单举例也显示了迭代器组合器 FP 风格

  基本迭代器工厂

  itertools 中所有都可以用纯 Python 轻松地实现为生成器在 Python 2.3+ 中包含该模块要点是为些有用提供标准行为和名称尽管员可以编写他们自己版本但是每个人实际创建变体都会有点不兼容但是方面是要以高效率 C 代码实现迭代器组合器使用 itertools 将比编写您自己组合器稍微快标准文档显示了每个 itertools 等价纯 Python 实现所以不需要在本文中重复这些内容了

  itertools 中再基本不过了 - 而且命名也完全区别 - 这样从该模块导入所有名称可能就有意义了例如 enumerate 可能明显地出现在 itertools 中但是它在 Python 2.3+ 中却是个内置值得注意您可以用 itertools 很方便地表达 enumerate :

from itertools import *
enumerate = lambda iterable: izip(count, iterable)


  让我们首先看下几个 itertools 它们 没有将其它迭代器作为基础而完全是“从头”创建迭代器 times 返回个多次产生同对象迭代器;在本质上能力比较有用但它确实可以很好地替代使用过多 xrange 和索引变量从而可以简单地重复个操作不必使用:

for i in xrange(1000):
  do_something


  您现在就可以使用更中性:

for _ in times(1000):
  do_something


  如果 times 只有个参数那么它只会重复产生 None repeat 类似于 times 但它无界地返回同对象不管是在包含独立 条件循环中还是在象 izip 和 imap 这样组合器中这个迭代器都很有用

   count 有点类似于 repeat 和 xrange 交叉 count 无界地返回连续整数(以可选参数为开始)但是如果 count 当前不支持溢出到现在正确 longs那么您可能还是要使用 xrange(n,sys.max) ;它并不是完全无界但是对于大多数用途它实际上是回事类似于 repeat count 在其它迭代器组合器内部特别有用

  组合

  我们已经顺便提到了 itertools 中几个实际组合 ilter 、 izip 和 imap 作用就象您会期望从它们相应序列上获得作用 ilterfalse 很方便所以您不需要去掉 lambda 和 def 中谓词(而且这还节省了大量开销)但是在功能上您可以将 ilterfalse 定义为(大致情况忽略了 None 谓词):

def ilterfalse(predicate, iterable):
   ilter(lambda predicate: not predicate, iterable)


   dropwhile takewhile 根据谓词对迭代器进行划分 dropwhile 在直到满足某个谓词 的前忽略所产生元素 takewhile 在满足某个谓词 时就终止 dropwhile 跳过迭代器不定数目元素所以它可能直到某个延迟后才开始迭代 takewhile 马上开始迭代但是如果被传入谓词变为真那么就终止迭代器

   islice 基本上就是列表分片迭代器版本您可以指定开始、停止和步长就象使用常规如果给定了开始那么会删除大量元素直到被传递迭代器到达满足条件元素为止这是另个我认为可以对 Python 进行改进情形 - 迭代器最好只识别片就象列表所做(作为 islice 行为同义词)

  最后 starmap 在 imap 基础上略微有些变化如果这个作为参数传递获取多个参数那么被传递 iterable 会产生大小适合元组这基本上和包含多个被传入 iterable imap 相同只不过它包含先前和 izip 结合在 iterables 集合

  深入探讨

  itertools 中包含个很好开始不使用其它只用这些就可以让 Python 员更轻松地利用和组合迭代器般说来迭代器广泛使用对 Python 未来无疑是很重要但是除了过去所包含内容以外我还要对该模块将来更新提几点建议您可以立即很方便地使用这些 - 当然如果它们是后来被包含进来那么名称或接口细节会有所区别

  种可能会很通用类别是些将多个 iterable 作为参数随后从每个 iterable 产生单独元素和此相对照 izip 产生元素元组而 imap 产生从基本元素计算而来我头脑中很清晰两个安排是 chain 和 weave 个在效果上类似于序列并置(但是有点惰性)在您可能使用纯序列中例如:

for x in ('a','b','c') + (1, 2, 3):
  do_something(x)


  对于 iterables您可以使用:

for x in chain(iter1, iter2, iter3):
  do_something(x)


  Python 实现是:

  清单 3. chain 样本实现

def chain(*iterables):
  for iterable in iterables:
    for item in iterable:
      yield item


  使用 iterables您还可以通过使它们分散排列来组合几个序列还没有任何对序列执行这样相同操作内置语法但是 weave 本身也非常适用于完整序列下面是可能实现(Magnus Lie Hetland 提出了 comp.lang.python 类似):

  清单 4. weave 样本实现

def weave(*iterables):
  "Intersperse several iterables, until all are exhausted"
  iterables = map(iter, iterables)
  while iterables:
    for i, it in enumerate(iterables):
      try:
        yield it.next
      except StopIteration:
        del iterables[i]


  让我来演示下 weave 行为从实现上看不是很明显:

>>> for x in weave('abc', xrange(4), [10,11,12,13,14]):
...  pr x,
...
a 0 10 b 1 11 c 2 12 13 3 14


  即使些迭代器到达终点但其余迭代器会继续产生值直到在某时刻产生了所有可用值为止

  我将另外只提出个可行 itertools 提出这个主要是受到了构思问题编程思路方法启发 icompose 和上面提出 ireduce 存在某种对称但是在 ireduce 将值(惰性)序列传递给某个并产生每个结果地方 icompose序列应用于每个前趋返回值可以把 ireduce 用于将事件序列传递给长期活动对象而 icompose 可能将对象重复地传递给返回新对象赋值种思路方法是相当传统考虑事件 OOP 思路方法而第 2种思路更接近于 FP

  以下是可能 icompose 实现:

  清单 5. icompose 样本实现

def icompose(functions, initval):
  currval = initval
  for f in functions:
    currval = f(currval)
    yield currval


  结束语

  迭代器 - 被认为是惰性序列 - 是功能强大概念它开启了 Python 编程新样式但是在只把迭代器当作数据源和把它作为种序列来考虑的间存在着微妙差别这两种想法本质上哪种都不见得比另种更正确但是后者开创了操作编程事件种组合性简略表达思路方法 itertools 中组合(尤其是它可能产生些类似于我建议)接近于编程声明样式对我而言这些声明样式般都更不易出错且更强大

Tags:  if函数的使用 excel函数使用 组合函数 excel中函数的使用

延伸阅读

最新评论

发表评论