迭代器生成器装饰器
Posted think-cl
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了迭代器生成器装饰器相关的知识,希望对你有一定的参考价值。
1.迭代器
这里我们先来回顾一下什么是可迭代对象(Iterable)?
可以直接作用于for循环的对象统称为可迭代对象,即Iterable。
# 一是集合数据类型,如list、tuple、dict、set、str等;
# 二是generator,包括生成器和带yield的generator function。
可以被next()函数调用并不断返回下一个值(直到没有数据时抛出StopIteration错误)的对象称为迭代器,即Iterator。
Python 迭代器(Iterators)对象在遵守迭代器协议时需要支持如下两种方法。
__iter__(),返回迭代器对象自身。这用在 for 和 in 语句中。
__next__(),返回迭代器的下一个值。如果没有下一个值可以返回,那么应该抛出 StopIteration 异常。
#! /usr/bin/python #coding=utf-8 class Count(object): def __init__(self,low,high): self.low = low self.high = high def __iter__(self): return self def __next__(self): if self.low > self.high : raise StopIteration else: self.low = self.low + 1 return self.low - 1
>>> from test import Count >>> C = Count(5,10) >>> C <test.Count object at 0x7f84b94abe10> >>> for i in C : ... print (i,end = ‘ ‘) ... 5 6 7 8 9 10 >>> >>> C.__next__ <bound method Count.__next__ of <test.Count object at 0x7f84b94abe10>> >>> next(C) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/test/python/test.py", line 13, in __next__ raise StopIteration StopIteration >>> C = Count(5,6) >>> next(C) 5 >>> next(C) 6 >>> next(C) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/test/python/test.py", line 13, in __next__ raise StopIteration StopIteration
2.生成器
我们常说的生成器,
就是带有 yield
的函数
>>> def counter_generator(low, high): ... while low <= high: ... yield low ... low += 1 ... >>> for i in counter_generator(5,10): ... print(i, end=‘ ‘) ... 5 6 7 8 9 10
在 While 循环中,每当执行到 yield 语句时,返回变量 low 的值并且生成器状态转为挂起。在下一次调用生成器时,生成器从之前冻结的地方恢复执行然后变量 low 的值增一。生成器继续 while 循环并且再次来到 yield 语句...
当你调用生成器函数时它返回一个生成器对象。如果你把这个对象传入 dir() 函数,你会在返回的结果中找到 __iter__ 和 __next__ 两个方法名。
我们通常使用生成器进行惰性求值。这样使用生成器是处理大数据的好方法。如果你不想在内存中加载所有数据,你可以使用生成器,一次只传递给你一部分数据。
os.path.walk() 函数是最典型的这样的例子,它使用一个回调函数和当前的 os.walk 生成器。使用生成器实现节约内存。
我们可以使用生成器产生无限多的值。以下是一个这样的例子。
>>> def infinite_generator(start=0): ... while True: ... yield start ... start += 1 ... >>> for num in infinite_generator(4): ... print(num, end=‘ ‘) ... if num > 20: ... break ... 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
生成器是一定不能重复循环的
3. 闭包
闭包(Closures)是由另外一个函数返回的函数。我们使用闭包去除重复代码。在下面的例子中我们创建了一个简单的闭包来对数字求和
>>> def add_number(num): ... def adder(number): ... #adder 是一个闭包 ... return num + number ... return adder ... >>> a_10 = add_number(10) >>> a_10(21) 31 >>> a_10(34) 44 >>> a_5 = add_number(5) >>> a_5(3) 8
adder 是一个闭包,把一个给定的数字与预定义的一个数字相加。
4.装饰器
装饰器(Decorators)用来给一些对象动态的添加一些新的行为,我们使用过的闭包也是这样的。
装饰器其实就是一个闭包,把一个函数当做参数然后返回一个替代版函数
>>> def my_decorator(func): ... def wrapper(*args, **kwargs): ... print("Before call") ... result = func(*args, **kwargs) ... print("After call") ... return result ... return wrapper ... >>> @my_decorator ... def add(a, b): ... #我们的求和函数 ... return a + b ... >>> add(1, 3) Before call After call 4
定义函数的时候使用了*,意味着那些通过位置传递的参数将会被放在带有*前缀的变量中, 所以:
def one(*args): print args # 1 one() () one(1, 2, 3) (1, 2, 3) def two(x, y, *args): # 2 print x, y, args two(‘a‘, ‘b‘, ‘c‘) a b (‘c‘,)
第一个函数one只是简单地讲任何传递过来的位置参数全部打印出来而已,你们能够看到,在代码#1处我们只是引用了函数内的变量args, *args仅仅只是用在函数定义的时候用来表示位置参数应该存储在变量args里面。Python允许我们制定一些参数并且通过args捕获其他所有剩余的未被捕捉的位置参数,就像#2处所示的那样。
*操作符在函数被调用的时候也能使用。意义基本是一样的。当调用一个函数的时候,一个用*标志的变量意思是变量里面的内容需要被提取出来然后当做位置参数被使用。同样的,来看个例子:
def add(x, y): return x + y lst = [1,2] add(lst[0], lst[1]) # 1 3 add(*lst) # 2 3
#1处的代码和#2处的代码所做的事情其实是一样的,在#2处,python为我们所做的事其实也可以手动完成。这也不是什么坏事,*args要么是表示调用方法大的时候额外的参数可以从一个可迭代列表中取得,要么就是定义方法的时候标志这个方法能够接受任意的位置参数。
接下来提到的**会稍多更复杂一点,**代表着键值对的餐宿字典,和*所代表的意义相差无几,也很简单对不对:
def foo(**kwargs): print kwargs foo() {} foo(x=1, y=2) {‘y‘: 2, ‘x‘: 1}
当我们定义一个函数的时候,我们能够用**kwargs来表明,所有未被捕获的关键字参数都应该存储在kwargs的字典中。如前所诉,argshe kwargs并不是python语法的一部分,但在定义函数的时候,使用这样的变量名算是一个不成文的约定。和*一样,我们同样可以在定义或者调用函数的时候使用**。
dct = {‘x‘: 1, ‘y‘: 2} def bar(x, y): return x + y bar(**dct) 3
更加通用的装饰器
def logger(func): def inner(*args, **kwargs): #1 print "Arguments were: %s, %s" % (args, kwargs) return func(*args, **kwargs) #2 return inner
@logger def foo1(x, y=1): return x * y @logger def foo2(): return 2 foo1(5, 4) Arguments were: (5, 4), {} 20 foo1(1) Arguments were: (1,), {} 1 foo2() Arguments were: (), {} 2
请注意我们的函数inner,它能够接受任意数量和类型的参数并把它们传递给被包装的方法,这让我们能够用这个装饰器来装饰任何方法。
http://python.jobbole.com/81683/
以上是关于迭代器生成器装饰器的主要内容,如果未能解决你的问题,请参考以下文章