python--迭代器

转载:Source

一、什么是迭代器


我们先来看一个最简单的迭代器

class Positive:
    def __init__(self, limit):
        self.limit = limit
        self.n = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.n += 1
        if self.n <= self.limit:
            return self.n
        raise StopIteration

result = Positive(5)

for n in result:
    print(n)


1
2
3
4
5

这个迭代器的功能是返回小于等于指定值的 正整数

代码里的 result 变量同时是 可迭代对象迭代器

  • 可迭代对象:具有 __iter__ 方法,通过调用 iter(x) (等价于调用 x.iter())将会返回一个迭代器。
  • 迭代器:具有 __next__ 方法,通过调用 next(x) (等价于调用 x.next())每次返回一个结果, raise StopIteration 来结束迭代。

for n in result 在这里做了两件事,

  1. 通过iter(result) 获取了一个具有 __next__ 方法的迭代器假设为 x
  2. 循环调用 next(x) 获取返回值赋值到 n 变量上,直到捕获 StopIteration 异常。

因此我们可以手动调用 next 来实现 for in 的功能。

result = Positive(5)

result_iter = iter(result)  

while True:
    try:
        n = next(result_iter)  
        print(n)
    except StopIteration:
        break

很多网上的资料会把 __iter____next__ 定义在一个类里面,使这个类实例化出来的对象同时是 可迭代对象迭代器

然而__iter____next__是可以分别在两个类中实现的。

class Positive:
    def __init__(self, limit):
        self.limit = limit

    def __iter__(self):
        return Part(self.limit)

class Part:
    def __init__(self, limit):
        self.limit = limit
        self.n = 0

    def __next__(self):
        self.n += 1
        if self.n <= self.limit:
            return self.n
        raise StopIteration

result = Positive(5)

for n in result:
    print(n)

1
2
3
4
5

python 中的列表、集合、元组、字典也都是一个 可迭代对象,这表明这些类型可以直接作用于 for in 循环。

obj = [1, 2, 3]

print('是否有 __iter__ 方法:', hasattr(obj, '__iter__'))
print('是否有 __next__ 方法:', hasattr(obj, '__next__'))

print(dir(obj))


是否有 __iter__ 方法: True
是否有 __next__ 方法: False

['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__',
 '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', 
 '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', 
 '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
 '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', 
 '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 
 'remove', 'reverse', 'sort']

我们可以看到列表有 __iter__ 方法,代表是一个可迭代对象,没有 __next__ 代表其不是一个迭代器。

可以使用 iter 方法获取一个 迭代器 对象。

obj = [1, 2, 3]

new_obj = iter(obj)

print('是否有 __iter__ 方法:', hasattr(new_obj, '__iter__'))
print('是否有 __next__ 方法:', hasattr(new_obj, '__next__'))

print(dir(new_obj))


是否有 __iter__ 方法: True
是否有 __next__ 方法: True
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', 
'__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__',
 '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', 
 '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']

当然判断 可迭代对象迭代器 还有个更简单的方法,直接引入对应的类型用 isinstance 判断即可。

from collections.abc import Iterable, Iterator

obj = [1, 2, 3]

print('是否可迭代对象', isinstance(obj, Iterable))
print('是否迭代器', isinstance(obj, Iterator))


是否可迭代对象 True
是否迭代器 False

二、使用迭代器的场景


需要注意的是,以下的应用场景不使用迭代器也是可以实现的,绝大部分情况下使用迭代器是使代码更易读更易于重构,直接像对待数组一样使用 for in 来操作数据。

1、节省内存

假如我们有一份文件存着所有人类的姓名,这个文件可能有几百TB的大小。当我们要执行人类清除计划时会发现无法把这个文件一次读进内存。这时我们就可以通过迭代器的方法每次仅读取部分内容。

假如 我的很大 的文件长这样:

image

那我们可以通过一次读取一行的方式配合迭代器来载入数据,防止内存爆掉。

class Names:
   def __init__(self, path):
       self.f = open(path, 'r', encoding='utf-8')

   def __iter__(self):
       return self

   def __next__(self):
       name = self.f.readline()
       if name == '':
           raise StopIteration

       return name.strip()  

   def close(self):
       self.f.close()

def kill(name):
   print('清除人类:', name)

names = Names('names.txt')

for name in names:
   kill(name)

names.close()


清除人类: 王小明
清除人类: 鸣人    
清除人类: 柯南    
清除人类: 王路飞

2、流式处理数据

比如我们要从网络中一直读取数据并处理,由于数据是从火星发送的,每次耗时较长。如果我们等待数据读取完全再进行处理,既浪费了等待的时间没有处理数据,用户体验上也不友好。

这会用迭代器就能边读取数据,边处理数据,边展示数据。

import time

class Mars:
    
    _data = ['火星照片', '火星五星红旗照片', '火星人照片', 'end']
    _index = 0

    def __iter__(self):
        return self

    def read_data(self):
        
        time.sleep(1)
        data = self._data[self._index]
        self._index += 1
        return data

    def __next__(self):
        data = self.read_data()
        if data == 'end':
            raise StopIteration
        return data

mars = Mars()

for data in mars:
    print('读取到数据并处理:', data)


读取到数据并处理: 火星照片
读取到数据并处理: 火星五星红旗照片
读取到数据并处理: 火星人照片

3、无限的数据

有些数据是无限的,比如所有的正奇数,这会可以用迭代器来表示。

class Odd:
    def __init__(self):
        self.n = 1

    def __iter__(self):
        return self

    def __next__(self):
        value = self.n
        self.n += 2
        return value

for n in Odd():
    print(n)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会尽力回答你的问题。 首先,让我们来谈谈 Python 中的异常处理。在 Python 中,异常是程序在运行时遇到的错误或问题,它会导致程序停止运行并抛出一个异常。为了避免这种情况,我们可以使用 try/except 块来捕获并处理异常。例如: ``` try: # some code that might raise an exception except SomeException: # handle the exception ``` 其中,SomeException 是你想要捕获的异常类型。当代码运行到 try 块中的代码时,如果出现了 SomeException 异常,那么 except 块中的代码就会被执行。 接下来,让我们来谈谈 Python 中的对象。在 Python 中,一切都是对象,包括数字、字符串、函数等等。对象有一个类型,它定义了对象可以执行的操作。例如,数字类型可以执行加、减、乘等操作,字符串类型可以执行拼接、切片等操作。你也可以创建自己的对象,并定义它们的类型和操作。 最后,让我们来谈谈 Python 中的迭代器迭代器是一种对象,它可以让你逐个访问一个序列中的元素。Python 中的迭代器是通过 __iter__ 和 __next__ 方法实现的。__iter__ 方法返回一个迭代器对象,__next__ 方法返回序列中的下一个元素。例如: ``` class MyIterator: def __init__(self, data): self.data = data self.index = 0 def __iter__(self): return self def __next__(self): if self.index >= len(self.data): raise StopIteration result = self.data[self.index] self.index += 1 return result my_iter = MyIterator([1, 2, 3]) for item in my_iter: print(item) ``` 在上面的例子中,我们创建了一个名为 MyIterator 的迭代器对象。它有一个 data 属性,表示要迭代的序列,以及一个 index 属性,表示当前迭代的位置。__iter__ 方法返回 self,表示它本身就是一个迭代器对象。__next__ 方法返回序列中的下一个元素,并将 index 属性加 1。当迭代器遍历到序列末尾时,会抛出 StopIteration 异常,表示迭代结束。 希望这些信息能够对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值