zoukankan      html  css  js  c++  java
  • python3:iterable, iterator, generator,抽象基类, itertools的使用。

    目录:

    • iterable对象

    • iterator对象, 数据类型Iterator类

    • 数据类型Generator类。

    • 生成器表达式

    • collections.abc:容器的抽象基类。用于判断具体类。 

    • itertools模块:很多生成iterator的函数。

    • 延伸:duck-typing:理解python动态语言;再看继承和多态

    iterable -- 可迭代对象

    能够逐一返回其成员项的对象。包括:

    • 有序类型list, str, tuple
    • 无序类型dict, set
    • 任何定义了__iter__, __next__的类的对象。

    可迭代对象被可用于 for 循环以及许多其他需要一个序列的地方(zip()map() ...)。

    当一个可迭代对象作为参数传给内置函数 iter() 时,它会返回该对象的迭代器。这种iterator适用于对值集合的一次性遍历。

    例子:

    >>> a = [1, 2, None]
    >>> a
    [1, 2, None]
    >>> iter(a)
    <list_iterator object at 0x106a28f10>

    for语句会自动为可迭代对象创建一个的迭代器。用于循环期间的操作。

    iterator -- 迭代器

    用来表示一连串数据流的对象。重复调用迭代器的 __next__() 方法(或将其传给内置函数 next())将逐个返回流中的项。

    大多数容器对象都可以使用for循环语句:

    这幕后的机制就是,for循环内部使用了iter(), 为容器对象生成一个iterator对象。这个对象使用__next__()来逐一输出容器对象内的数据。

    数据类型--Iterator类型

    即对容器对象提供迭代的支持。

    container.__iter__()

    返回一个iterator对象。它有2个方法:

    • iterator.__iter__(): 返回自身,用于配合for和in语句。
    • iterator.__next__():  从容器中返回下一项item。

    Python定义了几种iterator对象,用于对序列类型list,str,tuple,字典dict, 和其他特别的形式进行迭代操作。

    数据类型--generator类型

    generator提供了实现迭代器的快捷方法。

    ⚠️:根据抽象基类: Generator继承自Iterator。但只是抽象的。

    方法:

    定义一个函数,在内部使用yield,这个函数就是一个generator函数,它是函数对象。类是<class function>。

    用它创建的对象,就是生成器对象。generator 对象。reverse(10).__class__是<class 'generator'>

    def reverse(data):
        for index in range(len(data)-1, -1, -1):
            yield data[index]
    
    >>> for char in reverse('golf'):
    ...     print(char)
    ...
    f
    l
    o
    g

    生成器表达式:

    一个更简便的方法定义generator

    >>> g = (x * x for x in range(10))
    >>> g
    <generator object <genexpr> at 0x1022ef630>
    >>> next(g)
    0
    >>> next(g)
    

    每调用一次next,就是循环一次。

    例子,演示定义一个生成可迭代对象的类:

    #linshi.py
    class Reverse:
        """Iterator for looping over a sequence backwards."""
        def __init__(self, data):
            self.data = data
            self.index = len(data)
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.index == 0:
                raise StopIteration
            self.index = self.index - 1
            return self.data[self.index]
    
     

    然后:

    >>> import linshi.py
    >>> import linshi
    >>> rev = linshi.Reverse('spam')
    >>> rev
    <linshi.Reverse object at 0x107c01430>
    >>> from collections.abc import Iterable
    >>> isinstance(rev, Iterable)
    True

    由此可知,定义的rev类的对象是可迭代的对象。


    collections.abc ---容器的抽象基类

    这个模块定义了一些抽象基类。它们可用于判断一个具体类是否具有某一特定的接口;例如,这个类是否可哈希,或其是否为映射类。

    abc是abstract base class的简写。是鸭子类型duck-typing的补充。

    ABC 引入了虚拟子类,这种类并非继承自其他类,但却仍能被 isinstance() 和 issubclass() 所认可;详见 abc 模块文档。

     class collections.abc.Iterable

     使用 isinstance(obj, Iterable) 可以检测一个类是否已经注册到了 Iterable 或者实现了 __iter__() 函数。

     例子:

    >>> from collections.abc import Iterator
    >>> isinstance([1,2], Iterable)
    True

     list实例并非继承自collections.abc.Iterable类。但是Iterable类是一个抽象基类。它提供了接口,用于判断list是否可迭代。

     listl类有__iter__方法, 因此可以判断它是可迭代的。


    itertools模块 

    itertools 模块中主要包含了一些用于生成迭代器的函数。

    例子:

    >>> import collections.abc as abc
    >>> import itertools as it
    >>> it.count
    <class 'itertools.count'>
    >>> a = it.count(10.3)
    >>> a
    count(10.3)
    >>> abc.Iterable
    <class 'collections.abc.Iterable'>
    >>> isinstance(a, abc.Iterable)
    True
    >>> isinstance(a, abc.Iterator)
    True

    解释:使用count()生成的对象a是可迭代的,同时也是迭代器。

    itertools模块提供的全部是处理迭代功能的函数,它们的返回值不是list,而是Iterator,只有用for循环迭代的时候才真正计算。


    (延伸)duck-typing 

    指一种编程风格,它并不依靠查找对象类型来确定其是否具有正确的接口,而是直接调用或使用其方法或属性。

    “看起来像鸭子,叫起来也像鸭子,那么肯定就是鸭子。”

    由于强调接口而非特定的类型,设计良好的代码可通过允许"多态替代"polymorphic substitution来提升灵活性。

    高级的动态语言都有这种编程风格,这和静态语言如java是不一样的。(摘录:Ruby元编程P116)

    在静态语言里,说对象的类型是T,是因为它属于T类(或是因为它实现了接口T),而在Ruby这样的动态语言,对象的"类型"并不严格的和它的类相关,"类型"只是对象能相应的一组方法。这种概念就是duck-typing

    duck-typing编程风格可以归类到多态中去。

    例子:

    class Eg1:
    
       def __init__(self, text):
    
           self.text = text
    
           self.sub_text = text.split(' ')
    
    
       def __getitem__(self, index):
    
           return self.sub_text[index]
    
    
       def __len__(self):
    
           return len(self.sub_text)
    
    
    o1 = Eg1('Hello, the wonderful new world!')
    
    print('长度:', len(o1))
    
    for i in o1:
    
       print(i)

    类Eg1。它的对象可以计算长度,可以循环,这是因为它通过object.__len__, object.__getitem__实现了相应的协议。这种无需关注它的类型,而只注重接口的编码风格,就是duck-typing。

    本例子:通过在类中定义了__getitem__方法,实例o1可以:

    • 做取值运算,o1[0],  []就是一个语法糖。相当于调用o1.__getitem(0),或type(o1).__getitem__(o1, 0)
    • 通过__getitem__,让o1支持序列协议sequence protocol。 可以使用iter(object)方法。

    ⚠️,实现了__getitem__和__len__就会被认为是序列。

    继承和多态

    例子:

    动物->鸭子,鸭子可以分为绿头鸭,黄鸭等等。这是继承。

    一只黄鸭的类型是黄鸭,它也是鸭子,也是动物。

    多态:

    对于一个实例对象,开发者只需要知道它是鸭子类型,就可以使用鸭子类型的各种实例方法,比如swimming()方法。无需知道它的子类型,即是黄鸭还是绿头鸭的问题。

    只有在运行代码时,后台代码才会自动判断它是什么子类型,然后沿着继承链条,找到鸭子类中的实例方法。

    重写方法:

    父类鸭子类,有swimming()方法,绿头鸭类,可以在自身重写swimming()方法,这样绿头鸭的实例就只会调用绿头鸭类的swimming()方法。当然可以在这个方法内使用super调用父类的swimming()方法,并对其修改。形成自身的swimming方法。


  • 相关阅读:
    LintCode: Convert Sorted Array to Binary Search Tree With Minimal Height
    LNMP企业应用部署全过程(基于DEDE后台)
    提高Web服务器并发响应的经历
    提高Web服务器并发响应的经历
    提高Web服务器并发响应的经历
    提高Web服务器并发响应的经历
    华为设备RIP实施和理论详解
    华为设备RIP实施和理论详解
    MySQL 官方 Docker 镜像的使用
    Docker之docker设置系统的环境变量
  • 原文地址:https://www.cnblogs.com/chentianwei/p/11928966.html
Copyright © 2011-2022 走看看