我们的上一个文章从很质朴的角度分析了究竟如何实践函数式的思想,但是由于Python是一个多范式的语言,既支持指令式,也支持函数式。但是,默认导入语言的函数只有map、filter和reduce(现在reduce也变成了库的一部分,不是默认导入了)。如果想更加方便的发挥Python函数编程的能力,实现我们的思路,我们必须借助以下几个内置库:itertools, functools和operator。

无论是不是采用函数编程范式,熟悉这些工具对我们写出高效、优美的程序都很有帮助。同时,手中的工具很可能也决定了思考问题的角度。就好比,不知道斧子的存在,手上只有一把小刀,那么很可能就只能用小刀砍树了。这篇文章我们主要介绍Itertools。文章主要分成两个部分:Iterator抽象

Itertool常用函数

1、Iterator的抽象

Python宏伟(吗?)的函数编程大厦其实建立在Iterator之上,所以我们需要先弄清楚这个东西。

概念上,Iterator就是一个代表数据流的对象(object)。从语言的角度,Iterator是一种数据类型(Type),Type就会定义能做什么,或者说只要有特定的行为就可以称为这个类型。Iterator类型定义了两种行为:__iter__()和__next__()。iter返回一个Iterator对象(如果本身就是iIterator,那么就返回自己本身),next返回容器中下一个元素。一旦实现了这两个函数,我们就可以任意使用Pyhton提供的任何针对Iterator的函数和功能了。比如 for loop以及我们接下来要讨论的Itertools。同时,可以调用next(Iterator)来手动提取下一个元素。

Python里面内置最常见的Iterator实例就是Sequence,包括list, tuple, range。当然,Sequence不仅仅实现了Iterator的两个功能,他们还实现了一些其他Sequence Type特有的行为,比如, a+b,a[i], len(a), max(a)等等。

另一个跟Iterator紧密两连的类型是Generator。如果一个类的iter函数采用Generator来实现,那么它会自动返回一个Iterator(其实是Generator Object),而这个东西已经是Iterator 类型。

那么如何构造一个Generator呢?其实他跟通常的函数一样,只不过采用yield作为返回,而不是return。每一次yield被调用的时候,函数会挂起整个进程,记录当前状态。当再一次被调用的时候,他会接着上面的状态进入下一个状态。通常Generator版本的Iterator会更加简洁。

讲了这么多理论,我们来看一个例子吧,如何实现一个自定一个数据结构,使他成为一个Iterator。

# 这两个函数/类 实现了相同的功能。

class PowTwo:

def __init__(self, max = 0):

self.max = max

def __iter__(self):

self.n = 0

return self

def __next__(self):

if self.n > self.max:

raise StopIteration

result = 2 ** self.n

self.n += 1

return result

# 但是Generator的版本更加方便

def powGen(max = 0):

n = 0

while n < max:

yield 2**n

n += 1

# 你可以从一个list建相应的Iterator

it = iter([1, 2, 3])

# 你可以手动获得下一个

nt = next(it)

nt = next(it)

nt = next(it)

我们实现Iterator主要有两个目的:他们可以是惰性的,节约内存

他们可以被传递到所有支持Iterator的函数中,最终形成强大复杂的功能

好了,稍微总结一下,我们需要Iterator来进一步进行函数编程,Generator/yield提供了简单的方式够在Iterator。接下来是更加有趣的东西啦!

2、Itertool,高效操作容器

itertool主要提供常见的迭代器抽象。这些函数主要是为了模拟一些经典的函数式编程语言,比如Haskell,SML等等。比如,在SML语言中,存在一个tabulate(f),它实现f(0), f(1), ...的功能,在Python中可以通过组合map和count实现:map(f, count)。

Itertool主要包含三类:无限迭代,有限迭代和组合迭代。需要注意的是,无限迭代都是懒惰的(Lazy), 这样在内存方面就会比较节省。

无限迭代包括三个函数:count(start, step), cycle(p)和repeat(elem, n) 。

count(10) ->10, 11, 12, .....

cycle('abcd') ->a, b, c, d, a, b, c, d, a, ....

repeat(10) ->10, 10, ...

有限迭代比较丰富。

# >>> accumulate: 带过程的reduce

# 有点Reduce的感觉是不是?!但是保留了过程。你想过如何用reduce实现吗?

accumulate([1,2,3], func=operator.add) # => [1,3,6]

cashflows = [1000, -90, -90, -90, -90]

list(accumulate(cashflows, lambda bal, pmt: bal*1.05 + pmt))

# [1000, 960.0, 918.0, 873.9000000000001, 827.5950000000001]

# >>> chain: append的升级版

chain('ABC', 'DEF')

#--> A B C D E F

# >>> compress: filter但是用预订的条件

compress('ABCDEF', [1,0,1,0,1,1])

# --> A C E F

# >>> dropwhile: 另一个常用的filter

# 他会丢弃不满足条件的元素,直到遇到一个满足条件的,然后后面的元素就不在filter了

dropwhile(lambda x: x<5, [1,4,6,4,1])

# --> 6 4 1

# >>> filterfalse: 返回错的!

filterfalse(lambda x: x%2, range(10))

# --> 0 2 4 6 8

# >>> groupby:连续的key分组

[k for k, g in groupby('AAAABBBCCDAABBB')] # --> A B C D A B

[list(g) for k, g in groupby('AAAABBBCCD')] # --> AAAA BBB CC D

# >>> islice: 高级索引

islice('ABCDEFG', 2) --> A B

islice('ABCDEFG', 2, 4) --> C D

islice('ABCDEFG', 2, None) --> C D E F G

islice('ABCDEFG', 0, None, 2) --> A C E G

# >>> starmap: map元素的第一个元素

starmap(pow, [(2,5), (3,2), (10,3)]) # --> 32 9 1000

# >>> takewhile: 跟dropwhile反过来

takewhile(lambda x: x<5, [1,4,6,4,1]) # --> 1 4

# >>> tee: 生产很多个迭代器

# >>> zip_longest: 另一个版本的zip

zip_longest('ABCD', 'xy', fillvalue='-') # --> Ax By C- D-

下面我们看组合迭代函数

# >>> product: 柯西积, ((x,y) for x in A for y in B)

product('ABCD', 'xy') # --> Ax Ay Bx By Cx Cy Dx Dy

# >>> permutations

permutations(range(3)) # --> 012 021 102 120 201 210

permutations('ABCD', 2) # --> AB AC AD BA BC BD CA CB CD DA DB DC

# >>> combinations: 有序的permutation

combinations('ABCD', 2) # --> AB AC AD BC BD CD

好!基本的工具就是这么多了,下面我们来看看如果用他们构造更加高级的函数吧!因为上面的工具在底层进行了内存和计算方面的优化,我们利用他们构造的函数同样集成了效率上的优势。当我们开始使用这些工具时,我们的思考方式会让我们的代码更加精简、优美,自动的呈现函数编程的模式:小工具连在一起,减少中间变量。同时,由于进行了向量化处理,我们代码效率也会相应提高。

下面列举一些非常常用的函数。

from itertools import *

from operator import itemgetter

# >>> take: Haskell的hello world.

def take(n, iteratable):

"Return first n items of the iterable as a list"

return list(islice(iterable, n))

# >>> tail: 同take

def tail(n, iteratable):

# tail(3, 'ABCDEFG') --> E F G

return iter(collections.deque(iterable, maxlen=n))

# >>> prepend: Haskell的 1::[2,3,4]

def prepend(value, iterator):

"Prepend a single value in front of an iterator"

# prepend(1, [2, 3, 4]) -> 1 2 3 4

return chain([value], iterator)

# >>> nth: 安全的索引, 你应该记得IndexException吧。。。

def nth(iterable, n, default=None):

"Returns the nth item or a default value"

return next(islice(iterable, n, None), default)

def all_equal(iterable):

# 返回True如果所有元素都相等

g = groupby(iterable)

return next(g, True) and not next(g, False)

# 从这里以后,我不写注释了,其实这些函数已经简单到不用任何注释了,

# 如果,不明白请打开terminal自己尝试一下!很有趣的!

def ncycles(iterable, n):

"Returns the sequence elements n times"

return chain.from_iterable(repeat(tuple(iterable), n))

def flatten(listOfLists):

"Flatten one level of nesting"

return chain.from_iterable(listOfLists)

def padnone(iterable):

return chain(iterable, repeat(None))

def n_cycles(iterable, n):

return chain.from_iterable(repeat(tuple(iterable), n))

def repeatfunc(func, times=None, *args):

if times is None:

return starmap(func, repeat(args))

return starmap(func, repeat(args, times))

def powerset(iterable):

# powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)

s = list(iterable)

return chain.from_iterable(combinators(s, r) for r in range(len(s) + 1))

def partition(pred, iterable):

'Use a predicate to partition entries into false entries and true entries'

# partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9

t1, t2 = tee(iterable)

return filterfalse(pred, t1), filter(pred, t2)

def unique_everseen(it, key=None):

# unique_everseen('AAAABBBCCDAABBB') --> A B C D

# unique_everseen('ABBCcAD', str.lower) --> A B C D

seen = set()

seen_add = seen.add

if key is None:

for ele in filterfalse(seen.__contains__, it)

seen_add(ele)

yield ele

else:

for ele in it:

k = key(ele)

if k not in seen:

seen_add(k)

yield ele

def unique_justseen(iterable, key=None):

"List unique elements, preserving order. Remember only the element just seen."

# unique_justseen('AAAABBBCCDAABBB') --> A B C D A B

# unique_justseen('ABBCcAD', str.lower) --> A B C A D

return map(next, map(itemgetter(1), groupby(iterable, key)))

def iter_except(func, exception, first=None):

""" Call a function repeatedly until an exception is raised.Converts a call-until-exception interface to an iterator interface.Like builtins.iter(func, sentinel) but uses an exception insteadof a sentinel to end the loop.Examples:iter_except(functools.partial(heappop, h), IndexError) # priority queue iteratoriter_except(d.popitem, KeyError) # non-blocking dict iteratoriter_except(d.popleft, IndexError) # non-blocking deque iteratoriter_except(q.get_nowait, Queue.Empty) # loop over a producer Queueiter_except(s.pop, KeyError) # non-blocking set iterator"""

try:

if first is not None:

yield first()

while True:

yield func()

except exception:

pass

def first_true(iterable, default=False, pred=None):

"""Returns the first true value in the iterable.If no true value is found, returns *default*If *pred* is not None, returns the first itemfor which pred(item) is true."""

# first_true([a,b,c], x) --> a or b or c or x

# first_true([a,b], x, f) --> a if f(a) else b if f(b) else x

return next(filter(pred, iterable), default)

def random_product(*args, repeat=1):

"Random selection from itertools.product(*args, **kwds)"

pools = [tuple(pool) for pool in args] * repeat

return tuple(random.choice(pool) for pool in pools)

参考:

Change Log2019-11-10 完成第一版

python itertool_函数式编程的Python实践(2):Itertool相关推荐

  1. 在 Python 中使用函数式编程的最佳实践!

    在函数式编程中,如何使用 Python 编写出优秀的代码? 作者 | Amandine Lee 译者 | 弯月 责编 | 屠敏 出品 | CSDN(ID:CSDNNews) 简介 Python 是一种 ...

  2. python采用函数式编程模式吗_Python函数与函数式编程

    1 函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也可以自己创 ...

  3. 白话 Python 的函数式编程

    今天和大家聊聊 Python 的函数式编程特性.所谓函数式编程,就是指代码中每一块都是不可变的(immutable),都是由 pure function 的形式组成.这里的 pure function ...

  4. Python的函数式编程--从入门到⎡放弃⎦

    很早以前就听说过了函数式编程,印象中是一种很晦涩难懂的编程模式,但却一直没有去进行了解. 恰好这周组内的周会轮到我主持,一时也没想到要分享什么.灵光一闪,就选定函数式编程这个主题吧,反正组里的同事都没 ...

  5. 【Python】函数式编程

    前言 函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基本 ...

  6. 用python处理excel数据做函数_如何使用python通过函数式编程完成excel中的数据处理及分析工作...

    Excel是数据分析中最常用的工具,本篇文章通过python与excel的功能对比介绍如何使用python通过函数式编程完成excel中的数据处理及分析工作.在Python中pandas库用于数据处理 ...

  7. 函数式编程|python的函数式编程

    面向过程,面向对象 面向过程: 分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了 面向对象: 把问题中的事务分解成各个对象,建立对象的目的不是为了完成一 ...

  8. 05 python 要点 (函数式编程)

    复习时先看看这个:https://blog.csdn.net/weixin_39880623/article/details/110153616? 第一章 函数式编程 一.生成器  (generato ...

  9. python基础 — 函数式编程

    前言:这篇文章比较抽象,先整理记录下来,工作中慢慢领悟. 1.函数式编程定义 简单说,"函数式编程"是一种"编程范式"(programming paradigm ...

最新文章

  1. 安卓上比较好的python开发软件-手机随时随地写Python,还可以开发安卓APP,太厉害了!...
  2. nova7修屏逛校园2021-07-07
  3. 洛谷 - P4173 残缺的字符串(多项式匹配字符串-NTT)
  4. nyoj-673-悟空的难题(数组标记)
  5. Apple Watch,其实是个老司“机”
  6. [Python] L1-051 打折-PAT团体程序设计天梯赛GPLT
  7. 23_Open_Loop
  8. VC dimension(Vapnik-Chervonenkis dimension)
  9. python ca模块_[转]常用的python模块及安装方法
  10. 用74HC573进行LED数码管驱动的编程
  11. 爬取王者荣耀皮肤图片
  12. gdb调试查看内存数据
  13. 黑马程序员————第三天
  14. 【算法】汇总:求解π值的算法
  15. 小学-知识与能力【10】
  16. 【python教程入门学习】ASCII码一览表,ASCII码对照表
  17. shrio简介--w3cschool
  18. 一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在 第10次落地时,共经过多少米?第10次反弹多高?
  19. 终于明白带宽和频率的关系
  20. Java Transaction silently rolled back because it has been marked as rollback-only问题解决

热门文章

  1. 使用Nginx+Lua(OpenResty)开发高性能Web应用
  2. Discuz代码研究-编码规范
  3. Git的SourceTree添加授权添加用户名与密码
  4. Basic各编码每个字符占用字节个数
  5. fiddler使用_为什么要使用fiddler抓包?抓包用来干什么?
  6. 基于h5的跳一跳游戏的开发与实现_「南宁小程序开发」企业开发小程序有哪些好处?...
  7. Navicat通过SSH连接远程服务器数据库
  8. avws扫描出来的漏洞怎么利用_漏洞扫描利用
  9. java thread sleep 效率_Thread.sleep(0):线程休眠0秒有什么意义!
  10. android百分比扩展枯,Android 增强版百分比布局库 为了适配而扩展