迭代

每一次对过程的重复称为一次迭代,而每一次迭代得到的结果会作为下一次迭代的初始值。例如:循环获取容器中的元素

可迭代对象 iterable

具有__iter__函数的对象,可以返回迭代器对象

# 语法

# 创建:
class 可迭代对象名称:
    def __iter__(self):
        return 迭代器

# 使用:
for 变量名 in 可迭代对象:
    语句

原理

迭代器 = 可迭代对象.__iter__()

while True:
    try:
        print(迭代器.__next__())
    except StopIteration:
        break

演示

message = "我是花果山水帘洞孙悟空"
# for item in message:
    # print(item)
    # 
# 1. 获取迭代器对象
iterator = message.__iter__()

# 2. 获取下一个元素
while True:
    try:
        item = iterator.__next__()
        print(item)
    # 3. 如果停止迭代则跳出循环
    except StopIteration:
        break

迭代器对象 iterator

可以被__next__函数调用并返回下一个值的对象

  • 说明:聚合对象通常是容器对象。
  • 作用:使用者只需通过一种方式,便可简洁明了的获取聚合对象中各个元素,而又无需了解其内部结构。
# 语法

class 迭代器类名:
    def __init__(self, 聚合对象):
        self.聚合对象= 聚合对象

    def __next__(self):
        if 没有元素:
            raise StopIteration
        return 聚合对象元素

演示

class StudentIterator:
    def __init__(self, data):
        self.__data = data
        self.__index = -1

    def __next__(self):
        if self.__index == len(self.__data) - 1:
            raise StopIteration()
        self.__index += 1
        return self.__data[self.__index]

class StudentController:
    def __init__(self):
        self.__students = []

    def add_student(self, stu):
        self.__students.append(stu)

    def __iter__(self):
        return StudentIterator(self.__students)

controller = StudentController()
controller.add_student("悟空")
controller.add_student("八戒")
controller.add_student("唐僧")

# for item in controller:
#     print(item) #
iterator = controller.__iter__()
while True:
    try:
        item = iterator.__next__()
        print(item) #
    except StopIteration:
        break

生成器generator

能够动态(循环一次计算一次返回一次)提供数据的可迭代对象

  • 在循环过程中,按照某种算法推算数据,不必创建容器存储完整的结果,从而节省内存空间。数据量越大,优势越明显。以上作用也称之为延迟操作或惰性操作,通俗的讲就是在需要的时候才计算结果,而不是一次构建出所有结果

生成器函数

含有yield语句的函数,返回值为生成器对象

  • 调用生成器函数将返回一个生成器对象,不执行函数体
  • yield翻译为产生或生成
# 语法

def 函数名():
    …
        yield 数据
    …

    # 调用:
    for 变量名 in 函数名():
        语句

执行过程

  1. 调用生成器函数会自动创建迭代器对象。
  2. 调用迭代器对象的__next__方法时才执行生成器函数。
  3. 每次执行到yield语句时返回数据,暂时离开。
  4. 待下次调用__next__方法时继续从离开处继续执行。

生成迭代器对象的大致规则如下

  1. yield关键字以前的代码放在__next__方法中。
  2. yield关键字后面的数据作为__next__方法的返回值。
def my_range(stop):
    number = 0
    while number < stop:
        yield number
        number += 1

for number in my_range(5):
    print(number) # 0 1 2 3 4

内置生成器

枚举函数 enumerate

遍历可迭代对象时,可以将索引与元素组合为一个元组

# 语法

for 变量 in enumerate(可迭代对象):
    语句

for 索引, 元素in enumerate(可迭代对象):
    语句

演示

list01 = [43, 43, 54, 56, 76]
# 从头到尾读 -- 读取数据
for item in list01:
    print(item)

# 非从头到尾读 -- 修改数据
for i in range(len(list01)):
    if list01[i] % 2 == 0:
        list01[i] += 1

for i, item in enumerate(list01): # -- 读写数据
    if item % 2 == 0:
        list01[i] += 1

zip

将多个可迭代对象中对应的元素组合成一个个元组,生成的元组个数由最小的可迭代对象决 定

# 语法

for item in zip(可迭代对象1, 可迭代对象2):
    语句

演示

list_name = ["悟空", "八戒", "沙僧"]
list_age = [22, 26, 25]

# for 变量 in zip(可迭代对象1,可迭代对象2)
for item in zip(list_name, list_age):
    print(item)
# ('悟空', 22)
# ('八戒', 26)
# ('沙僧', 25)

# 应用:矩阵转置
map = [
    [2, 0, 0, 2],
    [4, 2, 0, 2],
    [2, 4, 2, 4],
    [0, 4, 0, 4]
]
# new_map = []
# for item in zip(map[0],map[1],map[2],map[3]):
#     new_map.append(list(item))
# print(new_map)

# new_map = []
# for item in zip(*map):
#     new_map.append(list(item))

new_map = [list(item) for item in zip(*map)]
print(new_map)
# [[2, 4, 2, 0], [0, 2, 4, 4], [0, 0, 2, 0], [2, 2, 4, 4]]