Iterators、Generators、Decorator

迭代器

  1. iterator是通过一系列值来管理迭代(iteration)的对象。内置函数next(i)的每次调用都会从底层系列中生成一个后续元素,并引发一个StopIteration异常来表明没有其他元素。
  2. 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()函数内,首先打印日志,再紧接着调用原始函数

猜你喜欢

转载自blog.csdn.net/linshuo1994/article/details/83689090
今日推荐