zoukankan      html  css  js  c++  java
  • 设计模式---行为型设计模式【迭代器模式】

    迭代器模式可按顺序访问集合或聚合对象中的元素,同时又无须关注集合或聚合内部的实现细节。

    此模式很有用,Python语言为其提供了内置支持。实现此模式有三种方法:

    一、通过序列协议实现迭代器

    实现名为__getitem__()的特殊方法,此方法可接受整数做下标参数,这个下标从0开始,如果

    不能继续迭代了,那么应该抛出IndexError异常。

    实现__getitem__()方法后,可以像列表一样用中括号加下标的形式访问元素,例如“list[0]”

    这种方式只适合所求的值与下标有映射关系的场合,如果是“斐波那契”这种迭代关系就不适用了

    class AtoZ:
        def __getitem__(self, index):
            if 0 <= index < 26:
                return chr(index + ord('A'))
            raise IndexError()
    
    
    # 每个字母都是根据下标直接计算
    for letter in AtoZ():
        print(letter, end="")
    
    '''
    ABCDEFGHIJKLMNOPQRSTUVWXYZ
    '''

    二、通过双参数iter()函数实现迭代器

     还有个实现迭代器的办法是使用内置的iter()函数,但要传入两个参数,而不是像平常那样只传一个。

    采用这种形式的时候,第一个参数必须是callable的(函数、绑定方法或其他callable对象),

    第二个参数必须是个“标记值” ,没有"标记值"填None,Python才知道我们调用的是双参数iter()函数。

    使用此方法制作的迭代器每次迭代都会调用callable对象(调用时不传参数),

    只有当callable抛出StopIteration异常或返回标记值的时候,才停止迭代

    class Presidents:
        __names = ('George Washington[乔治·华盛顿]', 'John Adams[约翰·亚当斯]',
                   'Thomas Jefferson[托马斯·杰斐逊]', 'James Madison[詹姆斯·麦迪逊]',
                   'James Monroe[詹姆斯·门罗]', 'John Quincy Adams[约翰·昆西·亚当斯]',
                   'Andrew Jackson[安德鲁·杰克逊]', 'Martin van Buren[马丁·范布伦]',
                   'William Henry Harrison[威廉·亨利·哈里森]', 'John Tyler[约翰·泰勒]',
                   'James Knox Polk[詹姆斯·诺克斯·波尔克]', 'Zachary Taylor[扎卡里·泰勒]',
                   'Millard Fillmore[米勒德·菲尔莫尔]', 'Franklin Pierce[福兰克林·皮尔斯]',
                   'James Buchanan[詹姆斯·布坎南]', 'Abraham Lincoln[亚伯拉罕·林肯]',
                   'Andrew Johnson[安德鲁·约翰逊]', 'Ulysses Grant[尤里西斯·格兰特]',
                   'Rutherford B. Hayes[拉瑟福德·伯查德·海斯]', 'James A. Garfield[詹姆斯·加菲尔德]',
                   'Chester A Arthur[切斯特·艾伦·阿瑟]', 'Stephen Grover Cleveland[格罗佛·克利夫兰]',
                   'Benjamin Harrison[本杰明·哈里森]', 'Stephen Grover Cleveland[格罗佛·克利夫兰]',
                   'William McKinley[威廉·麦金利]', 'Theodore Roosevelt[西奥多·罗斯福]',
                   'William Howard Taft[威廉·霍华德·塔夫脱]', 'Thomas Woodrow Wilson[托马斯·伍德罗·威尔逊]',
                   'Warren Gamaliel Harding[沃伦·甘梅利尔·哈定]', 'John Calvin Coolidge[小约翰·卡尔文·柯立芝]',
                   'Herbert Clark Hoover[赫伯特·克拉克·胡佛]', 'Franklin Delano Roosevelt[富兰克林·德拉诺·罗斯福]',
                   'Harry S. Truman[哈里·S·杜鲁门]', 'Dwight David Eisenhower[德怀特·戴维·艾森豪威尔]',
                   'John Fitzgerald Kennedy[约翰·费茨杰拉德·肯尼迪]', 'Lyndon Baines Johnson[林登·贝恩斯·约翰逊]',
                   'Richard Milhous Nixon[理查德·米尔豪斯·尼克松]', 'Gerald Rudolph Ford    [杰拉尔德·鲁道夫·福特]',
                   'James Earl Carter[吉米·卡特]', 'Ronald Wilson Reagan[罗纳德·威尔逊·里根]',
                   'George Herbert Walker Bush[乔治·赫伯特·沃克·布什]', 'Bill Clinton[比尔·克林顿]',
                   'George Walker Bush[乔治·沃克·布什]', 'Barack Hussein Obama[贝拉克·奥巴马]',
                   'Donald John Trump[唐纳德·特朗普]',)
    
        def __init__(self, first=None):
            self.index = (-1 if first is None else
                          Presidents.__names.index(first) - 1)
    
        def __call__(self):
            self.index += 1
            if self.index < len(Presidents.__names):
                return Presidents.__names[self.index]
            raise StopIteration()
    
    
    def main():
        for president in iter(Presidents("Ronald Wilson Reagan[罗纳德·威尔逊·里根]"), None):
            print(president, end="  *  ")
        print()
        for president in iter(Presidents("Ronald Wilson Reagan[罗纳德·威尔逊·里根]"),
                              "Barack Hussein Obama[贝拉克·奥巴马]"):
            print(president, end="  *  ")
    
    
    if __name__ == '__main__':
        main()
    
    '''
    Ronald Wilson Reagan[罗纳德·威尔逊·里根]  *  George Herbert Walker Bush[乔治·赫伯特·沃克·布什]  *  Bill Clinton[比尔·克林顿]  *  George Walker Bush[乔治·沃克·布什]  *  Barack Hussein Obama[贝拉克·奥巴马]  *  Donald John Trump[唐纳德·特朗普]  *  
    Ronald Wilson Reagan[罗纳德·威尔逊·里根]  *  George Herbert Walker Bush[乔治·赫伯特·沃克·布什]  *  Bill Clinton[比尔·克林顿]  *  George Walker Bush[乔治·沃克·布什]  *  
    '''

    三、通过迭代器协议实现迭代器

    该协议要求类必须有名为__iter__()的特殊方法,而且该方法要返回迭代器对象。

    迭代器对象的__iter__()方法必须返回迭代器自身,而__next__()方法则返回下一个元素,

    如果没有元素可供迭代,则抛出StopIteration异常。

    而要实现__iter__()方法,最容易地方式则是令其成为生成器,或令其返回生成器,因为生成器本身就符合迭代器协议。

    创建一个“包(bag)”类,它与set类似,但其中可容纳重复的元素。为这个包增加迭代功能,现在我们用第三种方式来实现。

    ---包(bag)类:

    class Bag:
        '''
        Bag:与集合类似,只是元素允许重复
        '''
        def __init__(self, items=None):
            self.__bag = {}
            if items is not None:
                for item in items:
                    self.add(item)
    
        def add(self, item):
            self.__bag[item] = self.__bag.get(item, 0) + 1
    
        def __delitem__(self, item):
            # del bag['xx']
            if self.__bag.get(item) is not None:
                self.__bag[item] -= 1
                if self.__bag[item] <= 0:
                    del self.__bag[item]
            else:
                raise KeyError(str(item))
    
        def count(self, item):
            return self.__bag[item]
    
        def __len__(self):
            # len(bag)
            return sum(count for count in self.__bag.values())
    
        def __contains__(self, item):
            # 'xx' in bag
            return item in self.__bag
    
        def __str__(self):
            return self.__bag.__str__()

    --实现__iter__()方法,令其成为生成器:

    class Bag:
        '''
        Bag:与集合类似,只是元素允许重复
        '''# 实现__iter__()方法,令其成为生成器
        def __iter__(self):
            for item, count in self.__bag.items():
                for _ in range(count):
                    yield item
        
    if __name__ == '__main__':
        print({'a': 1, 'b': 1}.items())
        # dict_items([('a', 1), ('b', 1)])

    --实现__iter__()方法,令其返回生成器:

    class Bag:
        '''
        Bag:与集合类似,只是元素允许重复
        '''
    
        # 实现__iter__()方法,令其返回生成器
        def __iter__(self):
            return (item for item, count in self.__bag.items() 
                    for _ in range(count))
    
    if __name__ == '__main__':
        print({'a': 1, 'b': 1}.items())
        # dict_items([('a', 1), ('b', 1)])

    尽管这个Bag写的很好,但大家别忘了,标准库里还有个类已经实现了此功能,那就是collections.Counter

  • 相关阅读:
    绘图QPainter-画刷
    绘图QPainter-画笔
    pyqt5-多线程QThread类
    升级时出现错误的解决办法
    打包pyinstaller
    多文档界面QMdiArea
    停靠窗口QDockWidget
    堆叠窗口QStackedWidget
    VC运行库版本不同导致链接.LIB静态库时发生重复定义问题的一个案例分析和总结
    【一】ODB
  • 原文地址:https://www.cnblogs.com/staff/p/11653569.html
Copyright © 2011-2022 走看看