10.迭代模式

定义

  • 提供一种方法顺序地访问一组聚合对象(一个容器)中的各个元素,而又不需要暴露该对象的内部细节。
  • 迭代器一般至少有以下两种方法。
    • 获取当前所指向的元素:current()
    • 将指针移至下一个元素:next()
  • 也可以增加一些方法,比如实现从后往前遍历。一些更为丰富的迭代器功能如下:
    • 将指针移至起始的位置:toBegin()
    • 将指针移至结尾的位置:toEnd()
    • 获取当前所指向的元素:current()
    • 将指针移至下一个元素:next()
    • 将指针移至上一个元素:previous()

迭代模式的抽象模型

代码框架

class BaseIterator:
    """迭代器"""

    def __init__(self, data):
        self.__data = data
        self.toBegin()

    def toBegin(self):
        """将指针移至起始位置"""
        self.__curIdx = -1

    def toEnd(self):
        """将指针移至结尾位置"""
        self.__curIdx = len(self.__data)

    def next(self):
        """移动至下一个元素"""
        if (self.__curIdx < len(self.__data) - 1):
            self.__curIdx += 1
            return True
        else:
            return False

    def previous(self):
        "移动至上一个元素"
        if (self.__curIdx > 0):
            self.__curIdx -= 1
            return True
        else:
            return False

    def current(self):
        """获取当前的元素"""
        return self.__data[self.__curIdx] if (self.__curIdx < len(self.__data) and self.__curIdx >= 0) else None

例子

class Customer:  
    """客户"""  
  
    def __init__(self, name):  
        self.__name = name  
        self.__num = 0  
        self.__clinics = None  
  
    def getName(self):  
        return self.__name  
  
    def register(self, system):  
        system.pushCustomer(self)  
  
    def setNum(self, num):  
        self.__num = num  
  
    def getNum(self):  
        return self.__num  
  
    def setClinic(self, clinic):  
        self.__clinics = clinic  
  
    def getClinic(self):  
        return self.__clinics  
  
  
class NumeralIterator:  
    """迭代器"""  
  
    def __init__(self, data):  
        self.__data = data  
        self.__curIdx = -1  
  
    def next(self):  
        """移动至下一个元素"""  
        if (self.__curIdx < len(self.__data) - 1):  
            self.__curIdx += 1  
            return True  
        else:  
            return False  
  
    def current(self):  
        """获取当前的元素"""  
        return self.__data[self.__curIdx] if (self.__curIdx < len(self.__data) and self.__curIdx >= 0) else None  
  
  
class NumeralSystem:  
    """排号系统"""  
  
    __clinics = ("1号分诊室", "2号分诊室", "3号分诊室")  
  
    def __init__(self, name):  
        self.__customers = []  
        self.__curNum = 0  
        self.__name = name  
  
    def pushCustomer(self, customer):  
        customer.setNum(self.__curNum + 1)  
        click = NumeralSystem.__clinics[self.__curNum % len(NumeralSystem.__clinics)]  
        customer.setClinic(click)  
        self.__curNum += 1  
        self.__customers.append(customer)  
        print("%s 您好!您已在%s成功挂号,序号:%04d,请耐心等待!"  
              % (customer.getName(), self.__name, customer.getNum()))  
  
    def getIterator(self):  
        return NumeralIterator(self.__customers)  
  
  
def testHospital():  
    numeralSystem = NumeralSystem("挂号台")  
    lily = Customer("Lily")  
    lily.register(numeralSystem)  
    pony = Customer("Pony")  
    pony.register(numeralSystem)  
    nick = Customer("Nick")  
    nick.register(numeralSystem)  
    tony = Customer("Tony")  
    tony.register(numeralSystem)  
    print()  
  
    iterator = numeralSystem.getIterator()  
    while iterator.next():  
        customer = iterator.current()  
        print("下一位病人 %04d(%s) 请到 %s 就诊。"  
              % (customer.getNum(), customer.getName(), customer.getClinic()))  
  
  
testHospital()

python 中的迭代器

可以直接作用于 for 循环的对象统称为可迭代对象(Iterable) ,有以下两种

  • 集合数据类型,如 list、tuple、dict、set、str 等。
  • 生成器(Generator),包括 () 语法定义的生成器和带 yield 的 generator 函数。
#  方法一:使用()定义生成器
gen = (x * x for x in range(10))

#  方法二:使用yield定义generator函数
def fibonacci(maxNum):
    """斐波那契数列的生成器"""
    a = b = 1
    for i in range(maxNum):
        yield a # 相当于return,但是取走之后还向下运行
        a, b = b, a + b

def testIterable():
    print("方法一,0-9的平方数:")
    for e in gen:
        print(e, end="\t")
    print()

    print("方法二,斐波那契数列:")
    fib = fibonacci(10)
    for n in fib:
        print(n, end="\t")
    print()

    print("内置容器的for循环:")
    arr = [x * x for x in range(10)]
    for e in arr:
        print(e, end="\t")
    print()

    print()
    print(type(gen))
    print(type(fib))
    print(type(arr))

生成器(Generator)不但可以作用于 for 循环,还可以被 next() 函数不断调用并返回下一个值,直到最后抛出 StopIteration 错误,表示无法继续返回下一个值。可以被 next() 函数调用并不断返回下一个值的对象称为迭代器(Iterator)

可以使用 isinstance() 来判断一个对象是否为 Iterable 对象或 Iterator 对象

from typing import Iterable, Iterator  
#  方法一:使用()定义生成器  
gen = (x * x for x in range(10))  
  
  
#  方法二:使用yield定义generator函数  
def fibonacci(maxNum):  
    """斐波那契数列的生成器"""  
    a = b = 1  
    for i in range(maxNum):  
        yield a  
        a, b = b, a + b  
  
  
def testIterable():  
    print("方法一,0-9的平方数:")  
    for e in gen:  
        print(e, end="\t")  
    print()  
  
    print("方法二,斐波那契数列:")  
    fib = fibonacci(10)  
    for n in fib:  
        print(n, end="\t")  
    print()  
  
    print("内置容器的for循环:")  
    arr = [x * x for x in range(10)]  
    for e in arr:  
        print(e, end="\t")  
    print()  
  
    print()  
    print(type(gen))  
    print(type(fib))  
    print(type(arr))  
  
  
# 引入Iterable和Iterator  
  
def testIsIterator():  
    print("是否为Iterable对象:")  
    print(isinstance([], Iterable))  
    print(isinstance({}, Iterable))  
    print(isinstance((1, 2, 3), Iterable))  
    print(isinstance(set([1, 2, 3]), Iterable))  
    print(isinstance("string", Iterable))  
    print(isinstance(gen, Iterable))  
    print(isinstance(fibonacci(10), Iterable))  
    print("是否为Iterator对象:")  
    print(isinstance([], Iterator))  
    print(isinstance({}, Iterator))  
    print(isinstance((1, 2, 3), Iterator))  
    print(isinstance(set([1, 2, 3]), Iterable))  
    print(isinstance("string", Iterator))  
    print(isinstance(gen, Iterator))  
    print(isinstance(fibonacci(10), Iterator))  
  
  
testIsIterator()

运行结果:

是否为Iterable对象:
True
True
True
True
True
True
True
是否为Iterator对象:
False
False
False
True
False
True
True
  • 生成器(Generator) 既是 Iterable 对象,也是 Iterator 对象。
  • 列表(list)、字典(dict)、元组(tuple)、字符串是 Iterable 对象,却不是 Iterator 对象;集合(set)既是 Iterable 对象,也是 Iterator 对象。
  • Iterator 对象可以被 next() 函数不断调用并返回下一个值,直到最后抛出 StopIteration 错误,表示无法继续返回下一个值。
  • Iterable 对象不能被 next() 函数调用,可以用 iter() 函数将 Iterable 对象转成 Iterator 对象,如 iter([1,2,3])
def testNextItem():
    print("将Iterable对象转成Iterator对象:")
    l = [1, 2, 3]
    itrL = iter(l)
    print(next(itrL))
    print(next(itrL))
    print(next(itrL))
  • 要使自定义的类具有 Iterable 属性,需要实现 __iter__ 方法。
  • 要使自定义的类具有 Iterator 属性,需要实现 __iter____next__ 方法。
from typing import Iterable, Iterator  
  
  
class NumberSequence:  
    """生成一个间隔为step的数字系列"""  
  
    def __init__(self, init, step, max=100):  
        self.__data = init  
        self.__step = step  
        self.__max = max  
  
    def __iter__(self):  
        return self  
  
    def __next__(self):  
        if (self.__data < self.__max):  
            tmp = self.__data  
            self.__data += self.__step  
            return tmp  
        else:  
            raise StopIteration  
  
  
def testNumberSequence():  
    numSeq = NumberSequence(0, 5, 20)  
    print(isinstance(numSeq, Iterable))  
    print(isinstance(numSeq, Iterator))  
    # 先调 __iter__() 获取迭代器,再调用迭代器的__next__()。如果本身就是迭代器可以这么写。
    for n in numSeq:  
        print(n, end="\t")  
  
  
testNumberSequence()

模型说明

  • 设计要点
    • 了解容器的数据结构及可能的层次结构。
    • 根据需要确定迭代器要实现的功能,如 next()、previous()、current()、toBegin()、toEnd() 中的一个或几个。
  • 优缺点
    • 优点:
      • 迭代器模式将存储数据和遍历数据的职责分离。
      • 简化了聚合数据的访问方式。
      • 可支持多种不同的方式(如顺序和逆序)遍历一个聚合对象。
    • 缺点:
      • 需要额外增加迭代器的功能实现,增加新的聚合类时,可能需要增加新的迭代器。

应用场景

  • 集合的内部结构复杂,不想暴露对象的内部细节,只提供精简的访问方式。
  • 需要提供统一的访问接口,从而对不同的集合使用统一的算法。
  • 需要为一系列聚合对象提供多种不同的访问方式。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇