一、实验目的

  • 迭代器
  • 生成器
  • 生成器表达式
  • 闭包
  • 装饰器

二、知识要点

1.迭代器

迭代是Python最强大的功能之一,是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter()next()
字符串,列表或元组对象都可用于创建迭代器,例如:

list = [1, 2, 3, 4]
it = iter(list)
print("输出1:", next(it))
print("输出2:", next(it))

输出为:

输出1: 1
输出2: 2

迭代器对象也可以用常规的for循环语句进行遍历,例如我们在上面的代码后添加:

for x in it:
    print(x, end=" ")

最终会输出:

输出1: 1
输出2: 2
3 4   

1.1 把一个类作为一个迭代器
把一个类作为一个迭代器需要在类中实现两个方法__iter__()__next__()

  • __iter__()方法:该方法返回一个特殊的迭代器对象,,这个迭代器实现了__next__()方法并通过Stoplteration异常标识迭代的完成。
  • __next__()方法:返回下一个迭代器对象

1.2 StopIteration异常
StopIteration异常用于标识迭代的完成,防止出现无限循环的情况,在__next__()方法中我们可以设置在完成指定循环次数后出发StopIteration异常来结束迭代。

2.生成器

生成器是一个返回迭代器的函数,只能用于迭代操作,即生成器本质就是一个迭代器,在调用生成器运行的过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield的值,并在下一次执行next()方法时从当前位置继续运行。生成器自动创建了__iter__()__next__()方法且当发生器终结时会自动抛出StopIteration异常。
例如:

# 生成器实现range函数
def range_my(l, h):
    while l < h:
        yield l
        l += 1


for i in range_my(1, 10):
    print(i, end=" ")

输出结果为:

1 2 3 4 5 6 7 8 9

由上述代码我们容易得出在While循环中,每当执行到 yield语句时,返回变量low的值并且生成器状态转为挂起。在下一次调用生成器时,生成器从之前冻结的地方恢复执行然后变量low的值增一。生成器继续while循环并且再次来到yield语句…但是请注意:

生成器是无法重复使用的。

例如下面的例子:

# 生成器
def my_generator():
    print("Creat my generator")
    yield 'a'
    yield 'b'
    yield 'c'


g = my_generator()
print("第一次使用生成器")
for char in g:
    print(char)
print("第二次使用生成器")
for char in g:
    print(char)

输出为:

第一次使用生成器
Creat my generator
a
b
c
第二次使用生成器

可以看出,生成器不可重复使用,虽然我们无法创建一个课重复使用的生成器,但是我们可以创建一个对象,将他的__iter__方法调用而得到一个生成器,例如:

class Object_my(object):
    def __init__(self, l, h):
        self.l = l
        self.h = h

    def __iter__(self):
        count = self.l
        while self.h >= count:
            yield count
            count += 1


my_obj = Object_my(5, 10)
print("第一次:")
for i in my_obj:
    print(i, end=" ")
print("\n第二次:")
for i in my_obj:
    print(i, end=" ")

输出为:

第一次:
5 6 7 8 9 10 
第二次:
5 6 7 8 9 10

上面的my_obj并不是生成器或迭代器,因为它不具有__next__方法,只是一个可迭代对象,生成器是一定不能重复循环的。而my_obj.__iter__()是一个生成器,因为它是一个带有yield关键字的函数。

3.生成器表达式

有时简单的生成器可以用简洁的方式调用,就像不带中括号的链表推导式。这些表达式是为函数调用生成器而设计的。生成器表达式比完整的生成器定义更简洁,但是没有那么多变,而且通常比等价的链表推导式更容易记。
例如:

sum(i*i for i in range(10))

输出:285

4.闭包

在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。例如:

def who(name):
    def do(what):
        print(name, 'do', what)
    return do

zz = who('zz')
ln = who('ln')

zz("homework")
ln("housework")

输出:

zz do homework
ln do housework
5.装饰器

装饰器(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


print(add(1, 3))

输出为:

Before call
After call
4

由于装饰器较为难以理解,我将在之后的文章详细解释。

三、实验内容

1.迭代器

创建一个返回数字的迭代器,初始值为1,逐步递增1

  • 代码:
class My_num:
    def __iter__(self):
        self.a = 1
        return self

    def __next__(self):
        x = self.a
        self.a += 1
        return x


my_num = My_num()
myiter = iter(my_num)

print(next(my_num))
print(next(my_num))
print(next(my_num))
print(next(my_num))
print(next(my_num))
  • 结果:
1
2
3
4
5
2.StopIteration

在20次迭代后停止执行。

  • 代码:
class My_stop:
    def __iter__(self):
        self.a = 1
        return self

    def __next__(self):
        if self.a <= 20:
            x = self.a
            self.a += 1
            return x
        else:
            raise StopIteration


my_stop = My_stop()
myiter = iter(my_stop)
for x in myiter:
    print(x, end=" ")
  • 结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
3.生成器

本题要求通过生成器输出斐波那契亚数列前10项

  • 代码:
# 生成器的斐波那契亚数列
import sys

def finbonacci(n):  # 生成器函数-斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n):
            return
        yield a
        a, b = b, a + b
        counter += 1

f = finbonacci(10)

while True:
    try:
        print(next(f), end=" ")
    except StopIteration:
        sys.exit()
  • 结果:
0 1 1 2 3 5 8 13 21 34 55 

四、实验结果