迭代器
- iterator是通过一系列值来管理迭代(iteration)的对象。内置函数next(i)的每次调用都会从底层系列中生成一个后续元素,并引发一个StopIteration异常来表明没有其他元素。
- iterable通过iter(obj)生成一个迭代器(iterator)。基本的容器类型(列表、元组和集合);字符串可以生成字符的迭代;字典可以生成键的迭代;文件可以生成行的迭代
以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。集合数据类型如list、dict、str等是Iterable但不是Iterator。
例如,对于data = [1, 2, 4, 8],next(data)不能使用,而对于I = iter(data),next(I)可以使用。range()并不返回list,而是返回可迭代的range对象,这类似于dict.keys().values().items()
迭代器定义
collection的迭代器提供了一个关键行为:它提供一个名为__next__的特殊方法,该方法返回集合的下一个元素(如果有的话),或者引发一个StopIteration异常,以表明没有其他元素。
class SequenceIterator:
'''An iterator for any of Python s sequence types'''
def __init__(self,sequence):
"""Create an iterator for the given sequence."""
self._seq = sequence
self._k = -1 # will increment to 0 on first call to next
def __next__(self):
self._k += 1 # advance to next index
if self._k < len(self._seq):
return self._seq[self._k]
else:
raise StopIteration()
def __iter__(self):
"""按照约定,迭代器必须返回自己作为迭代器。"""
return self
判断是否可迭代
使用isinstance()判断一个对象是否是Iterable对象
from collections import Iterable,Iterator
isinstance([], Iterable)#True
isinstance((x for x in range(10)), Iterator) # True
isinstance([], Iterator) # False
isinstance({}, Iterator) # False
isinstance('abc', Iterator) # False
isinstance(iter([]), Iterator) # True
isinstance(iter('abc'), Iterator) # True
生成器
在Python中很少需要直接实现迭代器类,我们的首选方法是使用生成器语法。创建迭代器最方便的技术是使用生成器。生成器使用与函数非常类似的语法实现,但不使用return,执行yield语句。下面是求一个数的所有公约数
def factors(n):
results = [ ]
for k in range(1,n+1):
if n % k == 0:
results.append(k)
return results
生成器的实现如下,Python执行到一个yield语句指示下一个值。此时,该过程被临时中断,只在请求下一个值时才恢复。当控制流程结束(或无参数返回语句)时,会自动引发StopIteration异常
def factors(n):
for k in range(1,n+1):
if n % k == 0:
yield k
for fi in factors(100):
print(fi)
如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。在每次调用next()的时候执行,遇到yield语句返回(中断一下),再次执next()行时从上次返回的yield语句处继续执行
def odd():
print('step 1')
yield 1
print('step 2')
yield(3)
print('step 3')
yield(5)
o = odd()
next(o) # step 1 1
next(o) # step 2 3
next(o) # step 3 5
next(o)
#Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
#StopIteration
斐波拉契数列
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
return 'done'
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b #要把fib函数变成generator,只需要把print(b)改为yield b
a, b = b, a + b
n = n + 1
return 'done'
装饰器
装饰器(decorator)是放在函数定义前面的指令,Python在函数运行前,根据它来修改函数代码的行为。
def now():
print('2015-3-25')
f = now #由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数
f()# 2015-3-25
now.__name__ # 'now' #函数对象有一个__name__属性,可以拿到函数的名字
f.__name__ # 'now'
现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”
本质上,装饰器就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的装饰器,可以定义如下:
def log(func):
"""所以接受一个函数作为参数,并返回一个函数"""
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
借助Python的@语法,把decorator置于函数的定义处.调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:
@log
def now():
print('2015-3-25')
now()# call now(): 2015-3-25
把@log放到now()函数的定义处,相当于执行了语句
now = log(now) # (now=print功能+now())
由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数
函数运行时间
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.clock()
func(*args, **kwargs)
end_time = time.clock()
print("函数运行时间:" + str(end_time-start_time))
return wrapper