python函数详解(函数式编程的Python实践(2):Itertool)python初学 / python在函数式编程中的实践...

wufei123 发布于 2024-06-04 阅读(8)

我们的上一个文章从很质朴的角度分析了究竟如何实践函数式的思想,但是由于Python是一个多范式的语言,既支持指令式,也支持函数式但是,默认导入语言的函数只有map、filter和reduce(现在reduce也变成了库的一部分,不是默认导入了)。

如果想更加方便的发挥Python函数编程的能力,实现我们的思路,我们必须借助以下几个内置库:itertools, functools和operator无论是不是采用函数编程范式,熟悉这些工具对我们写出高效、优美的程序都很有帮助。

python函数详解(函数式编程的Python实践(2):Itertool)python初学 / python在函数式编程中的实践...

同时,手中的工具很可能也决定了思考问题的角度就好比,不知道斧子的存在,手上只有一把小刀,那么很可能就只能用小刀砍树了这篇文章我们主要介绍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。

# 这两个函数/类 实现了相同的功能classPowTwo:def__init__(self,max=0):self.max=maxdef__iter__(self):self.n=0returnself。

def__next__(self):ifself.n>self.max:raiseStopIterationresult=2**self.nself.n+=1returnresult# 但是Generator的版本更加方便

defpowGen(max=0):n=0whilen

(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,lambdabal,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(lambdax:x 6 4 1# >>> filterfalse: 返回错的!filterfalse(lambdax:x%2,range(10

))# --> 0 2 4 6 8# >>> groupby:连续的key分组[kfork,gingroupby(AAAABBBCCDAABBB)]# --> A B C D A B[list(g)for

k,gingroupby(AAAABBBCCD)]# --> AAAA BBB CC D# >>> islice: 高级索引islice(ABCDEFG,2)-->ABislice(ABCDEFG,2

,4)-->CDislice(ABCDEFG,2,None)-->CDEFGislice(ABCDEFG,0,None,2)-->ACEG# >>> starmap: map元素的第一个元素starmap

(pow,[(2,5),(3,2),(10,3)])# --> 32 9 1000# >>> takewhile: 跟dropwhile反过来takewhile(lambdax:x<5,[1,4,6,

4,1])# --> 1 4# >>> tee: 生产很多个迭代器# >>> zip_longest: 另一个版本的zipzip_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

# >>> permutationspermutations(range(3))# --> 012 021 102 120 201 210permutations(ABCD,2)# --> AB AC AD BA BC BD CA CB CD DA DB DC

# >>> combinations: 有序的permutationcombinations(ABCD,2)# --> AB AC AD BC BD CD好!基本的工具就是这么多了,下面我们来看看如果用他们构造更加高级的函数吧!因为上面的工具在底层进行了内存和计算方面的优化,我们利用他们构造的函数同样集成了效率上的优势。

当我们开始使用这些工具时,我们的思考方式会让我们的代码更加精简、优美,自动的呈现函数编程的模式:小工具连在一起,减少中间变量同时,由于进行了向量化处理,我们代码效率也会相应提高下面列举一些非常常用的函数。

fromitertoolsimport*fromoperatorimportitemgetter# >>> take: Haskell的hello world.deftake(n,iteratable

):"Return first n items of the iterable as a list"returnlist(islice(iterable,n))# >>> tail: 同takedef

tail(n,iteratable):# tail(3, ABCDEFG) --> E F Greturniter(collections.deque(iterable,maxlen=n))# >>> prepend: Haskell的 1::[2,3,4]

defprepend(value,iterator):"Prepend a single value in front of an iterator"# prepend(1, [2, 3, 4]) -> 1 2 3 4

returnchain([value],iterator)# >>> nth: 安全的索引, 你应该记得IndexException吧defnth(iterable,n,default=None):"Returns the nth item or a default value"

returnnext(islice(iterable,n,None),default)defall_equal(iterable):# 返回True如果所有元素都相等g=groupby(iterable

)returnnext(g,True)andnotnext(g,False)# 从这里以后,我不写注释了,其实这些函数已经简单到不用任何注释了,# 如果,不明白请打开terminal自己尝试一下!很有趣的!

defncycles(iterable,n):"Returns the sequence elements n times"returnchain.from_iterable(repeat(tuple(

iterable),n))defflatten(listOfLists):"Flatten one level of nesting"returnchain.from_iterable(listOfLists

)defpadnone(iterable):returnchain(iterable,repeat(None))defn_cycles(iterable,n):returnchain.from_iterable

(repeat(tuple(iterable),n))defrepeatfunc(func,times=None,*args):iftimesisNone:returnstarmap(func,repeat

(args))returnstarmap(func,repeat(args,times))defpowerset(iterable):# powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)

s=list(iterable)returnchain.from_iterable(combinators(s,r)forrinrange(len(s)+1))defpartition(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)returnfilterfalse(pred,t1),filter(pred,t2)defunique_everseen(it,key=None):# unique_everseen(AAAABBBCCDAABBB) --> A B C D

# unique_everseen(ABBCcAD, str.lower) --> A B C Dseen=set()seen_add=seen.addifkeyisNone:foreleinfilterfalse

(seen.__contains__,it)seen_add(ele)yieldeleelse:foreleinit:k=key(ele)ifknotinseen:seen_add(k)yieldele

defunique_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

returnmap(next,map(itemgetter(1),groupby(iterable,key)))defiter_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 instead

of a sentinel to end the loop. Examples: iter_except(functools.partial(heappop, h), IndexError) # priority queue iterator

iter_except(d.popitem, KeyError) # non-blocking dict iterator iter_except(d.popleft, IndexError) # non-blocking deque iterator

iter_except(q.get_nowait, Queue.Empty) # loop over a producer Queue iter_except(s.pop, KeyError) # non-blocking set iterator

"""try:iffirstisnotNone:yieldfirst()whileTrue:yieldfunc()exceptexception:passdeffirst_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 item for 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 xreturnnext(filter(pred,iterable),default

)defrandom_product(*args,repeat=1):"Random selection from itertools.product(*args, **kwds)"pools=[tuple

(pool)forpoolinargs]*repeatreturntuple(random.choice(pool)forpoolinpools)参考:https://docs.python.org/3.7

https://www.programiz.com/python-programming/generatorChange Log2019-11-10 完成第一版

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

河南中青旅行社综合资讯 奇遇综合资讯 盛世蓟州综合资讯 综合资讯 游戏百科综合资讯 新闻60339