大家都知道,python中有三大式,和三大器,前篇博客稍微举例说明了一下三大推导式,本篇文章也一样,稍微举例说明一下三大器:迭代器,生成器,装饰器。


迭代器

       我们知道像string、list、tuple、set、dictionary等容器对象可以使用for循环迭代。那为什么可以迭代呢,调用了什么方法呢。

举例:

for num in [10,20,30,40,50]:
    print(num)

1、在for循环中调用了list的__iter__()方法。这个方法返回一个迭代器对象。迭代器对象有一个方法__next__(),该方法返回list容器中的下一项。

2、当所有项都被迭代后,下一次调用__next__()将引发一个StopIteration异常,该异常将告诉for循环终止。

上面的例子中,也可以使用__iter__()和__next__()得到相同的结果。

lst = [10, 20, 30, 40, 50]
i = lst.__iter__()
print(i.__next__())
print(i.__next__())
print(i.__next__())
print(i.__next__())
print(i.__next__())

还可以调用更方便的iter()和next()来实现。

lst = [10, 20, 30, 40, 50]
i = iter(lst)
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))

1、可迭代器对象是一个能够一次返回一个成员的对象。

2、迭代器是一个同时在其内部实现了__iter__()和__next__()的对象。


生成器

       生成器是一个用于创建迭代器非常高效的函数。当生成器希望从函数返回数据时,使用yield语句而不是return。

       生成器的特殊之处在于,当yield被执行时,它会记住函数的状态以及执行的最后一条语句。因此,每次调用next()时,都会从上次中断的地方恢复。

       生成器非常简洁,因为__iter__()、next()和StopIteration代码是自动创建的。

举例:

# 求列表内相邻两数的平均值
def Avg(data):
    for i in range(0, len(data)-1):
        yield (data[i]+data[i+1])/2

lst = [10, 20, 30, 40, 50, 60, 70]
for i in Avg(lst):
    print(i)

#结果如下:
15.0
25.0
35.0
45.0
55.0
65.0
生成器表达式

       与列表推导式类似,为了使代码更紧凑、更简洁,可以编写紧凑的生成器表达式。

       生成器表达式动态地创建一个生成器,而不需要使用yield语句。

举例:

# 生成10到100之间的20个随机数
print(max(random.randint(10,100) for n in range(20)))

# 打印所有小于20的数字的立方和
print(sum(n*n*n for n in range(20)))

注意:不像列表推导式用[]包围,生成器表达式写在()中。


装饰器

      函数是python的“一等公民”。这意味着像整数、字符串、列表、模块等函数也可以动态创建和删除,传递给其它函数并作为值返回。

      在装饰器中也使用了“一等公民”特性。

      装饰器函数接收一个函数,向它添加一些功能(装饰)并返回它。

      常用的装饰器有@classmethod、@staticmethod、@property。

举例:

      定义一个装饰器,可以报告执行任何函数所需的时间。

import time


def timer(func):
    def calculate(*args, **kwargs):
        start_time = time.perf_counter()
        value = func(*args, **kwargs)
        end_time = time.perf_counter()
        runtime = end_time - start_time
        print(f'函数所需时间{runtime:.8f}秒')
        return value
    return calculate

@timer
def product(num):
    fact = 1
    for i in range(num):
        fact = fact *i+1
    return fact

@timer
def product_and_sum(num):
    p = 1
    for i in range(num):
        p = p *i+1
    s = 0
    for i in range(num):
        s = s + i + 1
    return (p, s)

@timer
def time_pass(num):
    for i in range(num):
        i +=1

p = product(10)
print('product of first 10nos.=', p)
p = product(20)
print('product of first 20nos.=', p)

fs = product_and_sum(10)
print('product and sum of first 10 nos.=', fs)
fs = product_and_sum(20)
print('product and sum of first 20 nos.=', fs)

time_pass(20)


#结果如下:
函数所需时间0.00000420秒
product of first 10nos.= 986410
函数所需时间0.00000327秒
product of first 20nos.= 330665665962404000
函数所需时间0.00000327秒
product and sum of first 10 nos.= (986410, 55)
函数所需时间0.00000467秒
product and sum of first 20 nos.= (330665665962404000, 210)
函数所需时间0.00000187秒

1、三个执行时间的函数: product()、time_pass()、product_and_sum()。参数和返回类型各不相同。却能够将相同的装饰器@timer应用到所有的对象上。

2、调用三个函数时传递的参数在*args, **kwargs中接收。

3、被调用的函数回返值在value中收集返回。

4、使用性能计数器,time.perf_counter()返回性能计数器的值,即小数形式的秒数值。函数两次调用之间的差异决定了执行一个函数所需的时间。

5、用类似的方法,可以为类中的方法定义装饰器。