python迭代器&生成器使用技巧(1):遍历、代理、生成器创建迭代、反向迭代

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shenziheng1/article/details/83503914

1. 手动遍历迭代器 next()

遍历一个可迭代对象中的所有元素,但是却不想使用for循环。为了手动的遍历可迭代对象,使用 next() 函数并在代码中捕获 StopIteration 异常。 通常来讲, StopIteration 用来指示迭代的结尾。 然而,如果手动使用 next() 函数的话,还可以通过返回一个指定值来标记结尾,比如 None 。读取一个文件的所有行实例。

def manual_iter(filename):
    with open(filename) as f:
        try:
            while True:
                line = next(f)
                print(line, end = '')
        except StopIteration:
            pass
        
manual_iter(filename = 'test.txt')      

############################

with open('test.txt') as f:
    while True:
        line = next(f, None)
        if line is None:
            break
        print(line, end='')
# >>> sorry
#     i really don't know how to choose?
#     go abroad, tencent, or alibaba?
#     but anyway,
#     i absolutely don't choose to huawei...    

迭代机制:获取迭代器+运行迭代器

items = [1, 2, 3]      
# Get the iterator
it = iter(items) # Invokes items.__iter__()
# Run the iterator
print( next(it) ) # 1 
print( next(it) ) # 2 
print( next(it) ) # 3 
print( next(it) ) # Traceback : StopIteration

2. 代理迭代

有的时候,我们需要构建自定义容器对象,里面包含有列表、元组或其他可迭代对象。并且直接在新容器对象上执行迭代操作。实际上我们只需要定义一个__iter__()方法,将迭代操作代理到容器内部的对象上去。

class Node:
    def __init__(self, value):
        self.value = value
        self._children = []
    
    def __repr__(self):
        return 'Node({!r})'.format(self.value)

    def add_child(self, node):
        self._children.append(node)
        
    def __iter__(self):
        return iter(self._children)

if __name__ == '__main__':
    root = Node(0)
    child1 = Node(1)
    child2 = Node(2)
    root.add_child(child1)
    root.add_child(child2)
    
    for tar in root:
        print(tar)
# >>> Node(1) Node(2) 

在上面代码中, __iter__() 方法只是简单的将迭代请求传递给内部的 _children 属性。

3. 使用生成器创建新的迭代模式

如果想实现一种新的迭代模式,可以使用生成器函数来定义。 下面是一个生产某个范围内浮点数的生成器:

def frange(start, stop, increment):
    x = start
    while x < stop:
        yield x       # pointer to next object
        x += increment
        
for num in frange(0, 4, 0.5):
    print(num)
# >>> 0 0.5 1.0 1.5 2.0 2.5 3.0 3.5

一个函数中需要有一个 yield 语句即可将其转换为一个生成器。 跟普通函数不同的是,生成器只能用于迭代操作。一个生成器函数主要特征是它只会回应在迭代中使用到的 next 操作。 一旦生成器函数返回退出,迭代终止。

4. 反向迭代

当我们需要反向迭代时,就需要reversed()函数进行处理。

a = [1, 2, 3, 4]
for num in reversed(a):
    print (num)
# >>> 4 3 2 1

反向迭代仅仅当对象的大小可预先确定或者对象实现了 __reversed__() 的特殊方法时才能生效。 如果两者都不符合,那必须先将对象转换为一个列表才行,比如:

"""
a = [1, 2, 3, 4]
for num in reversed(a):
    print (num)
# >>> 4 3 2 1
"""
f = open('test.txt')
for line in reversed(list(f)):
    print(line, end='')
# >>> i absolutely don't choose to huawei.but anyway.
#     go abroad, tencent, or alibaba?
#     i really don't know how to choose?
#     sorry.
  • 自定义类上实现 __reversed__() 方法来实现反向迭代
class Countdown:
    def __init__(self, start):
        self.start = start

    def __iter__(self):# Forward
        n = self.start
        while n > 0:
            yield n
            n -= 1
    
    def __reversed__(self):# Reverse
        n = 1
        while n <= self.start:
            yield n
            n += 1

for rr in reversed(Countdown(30)):
    print(rr)
for rr in Countdown(30):
    print(rr)

定义一个反向迭代器可以使得代码非常的高效, 因为它不再需要将数据填充到一个列表中然后再去反向迭代这个列表。

文章参考《python3-cookbook》

猜你喜欢

转载自blog.csdn.net/shenziheng1/article/details/83503914