【python进阶】迭代器和生成器

原文地址:https://blog.csdn.net/qq_41333582/article/details/82219190

一. 迭代

1. 迭代的概念

使用for循环遍历取值的过程叫做迭代,比如:使用for循环遍历列表获取值的过程

for value in [2, 3, 4]:
    print(value)

2. 可迭代对象

使用for循环遍历取值的对象叫做可迭代对象, 比如:列表、元组、字典、集合、range、字符串

3. 判断对象是否为可迭代对象

# 元组,列表,字典,字符串,集合,range都是可迭代对象
from collections import Iterable

# 判断对象是否是指定类型
result = isinstance((3, 5), Iterable)
print("元组是否是可迭代对象:", result)

result = isinstance([3, 5], Iterable)
print("列表是否是可迭代对象:", result)

result = isinstance({"name": "张三"}, Iterable)
print("字典是否是可迭代对象:", result)

result = isinstance("hello", Iterable)
print("字符串是否是可迭代对象:", result)

result = isinstance({3, 5}, Iterable)
print("集合是否是可迭代对象:", result)

result = isinstance(range(5), Iterable)
print("range是否是可迭代对象:", result)

result = isinstance(5, Iterable)
print("整数是否是可迭代对象:", result)

# 提示: 以后还根据对象判断是否是其它类型,比如以后可以判断函数里面的参数是否是自己想要的类型
result = isinstance(5, int)
print("整数是否是int类型对象:", result)

class Student(object):
    pass

stu = Student()
result = isinstance(stu, Iterable)

print("stu是否是可迭代对象:", result)

result = isinstance(stu, Student)

print("stu是否是Student类型的对象:", result)

4. 自定义可迭代对象

自定义可迭代对象: 在类里面定义iter方法创建的对象就是可迭代对象

二. 迭代器

1. 自定义迭代器对象

自定义迭代器对象: 在类里面定义iternext方法创建的对象就是迭代器对象

from collections import Iterable
from collections import Iterator

# 自定义可迭代对象: 在类里面定义__iter__方法创建的对象就是可迭代对象
class MyList(object):

    def __init__(self):
        self.my_list = list()

    # 添加指定元素
    def append_item(self, item):
        self.my_list.append(item)

    def __iter__(self):
        # 可迭代对象的本质:遍历可迭代对象的时候其实获取的是可迭代对象的迭代器, 然后通过迭代器获取对象中的数据
        my_iterator = MyIterator(self.my_list)
        return my_iterator


# 自定义迭代器对象: 在类里面定义__iter__和__next__方法创建的对象就是迭代器对象
class MyIterator(object):

    def __init__(self, my_list):
        self.my_list = my_list

        # 记录当前获取数据的下标
        self.current_index = 0

        # 判断当前对象是否是迭代器
        result = isinstance(self, Iterator)
        print("MyIterator创建的对象是否是迭代器:", result)

    def __iter__(self):
        return self

    # 获取迭代器中下一个值
    def __next__(self):
        if self.current_index < len(self.my_list):
            self.current_index += 1
            return self.my_list[self.current_index - 1]
        else:
            # 数据取完了,需要抛出一个停止迭代的异常
            raise StopIteration


my_list = MyList()
my_list.append_item(1)
my_list.append_item(2)
result = isinstance(my_list, Iterable)

print(result)

for value in my_list:
    print(value)

执行结果:

True
MyIterator创建的对象是否是迭代器: True
1
2

2. iter()函数和next()函数

  • iter函数: 获取可迭代对象的迭代器,会调用可迭代对象身上的iter方法
  • next函数: 获取迭代器中下一个值,会调用迭代器对象身上的next方法

3. for循环的本质

  • 遍历的是可迭代对象

    for item in Iterable 循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束。

  • 遍历的是迭代器

    for item in Iterator 循环的迭代器,不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束。

4. 利用斐波那契数列实现迭代器

class Fibonacci(object):

    def __init__(self, num):
        # num:表示生成多少fibonacci数字
        self.num = num
        # 记录fibonacci前两个值
        self.a = 0
        self.b = 1
        # 记录当前生成数字的索引
        self.current_index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.current_index < self.num:
            result = self.a
            self.a, self.b = self.b, self.a + self.b
            self.current_index += 1
            return result
        else:
            raise StopIteration


fib = Fibonacci(5)
# value = next(fib)
# print(value)

for value in fib:
    print(value)

三. 生成器

1. 生成器的概念

生成器是一类特殊的迭代器,它不需要再像上面的类一样写iter()和next()方法了, 使用更加方便,它依然可以使用next函数和for循环取值

2. 创建生成器的两种方式

  • 第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )
  • 在def函数里面看到有yield关键字那么就是生成器

总结:

在使用生成器实现的方式中,我们将原本在迭代器next方法中实现的基本逻辑放到一个函数中来实现,但是将每次迭代返回数值的return换成了yield,此时新定义的函数便不再是函数,而是一个生成器了。 
简单来说:只要在def中有yield关键字的 就称为 生成器

3.yield 和 return 对比

  • 使用了yield关键字的函数不再是函数,而是生成器。(使用了yield的函数就是生成器)
  • 代码执行到yield会暂停,然后把结果返回出去,下次启动生成器会在暂停的位置继续往下执行
  • 每次启动生成器都会返回一个值,多次启动可以返回多个值,也就是yield可以返回多个值
  • return只能返回一次值,代码执行到return语句就停止迭代,抛出停止迭代异常

4. 使用 send方法可以为生成器传参

注意:如果第一次启动生成器使用send方法,那么参数只能传入None,一般第一次启动生成器使用next函数 
总结:

生成器创建有两种方式,一般都使用yield关键字方法创建生成器 
yield特点是代码执行到yield会暂停,把结果返回出去,再次启动生成器在暂停的位置继续往下执行

猜你喜欢

转载自blog.csdn.net/weixin_40283570/article/details/82769970