Python中的循环列表迭代器


99

我需要遍历一个循环列表,每次从最后一次访问的项目开始,可能要多次。

用例是一个连接池。客户端请求连接,迭代器检查指向的连接是否可用并返回,否则循环直到找到可用的连接。

有没有一种精巧的方法可以在Python中做到这一点?

Answers:


159

使用itertools.cycle,这是其确切目的:

from itertools import cycle

lst = ['a', 'b', 'c']

pool = cycle(lst)

for item in pool:
    print item,

输出:

a b c a b c ...

(显然,永远循环)


为了手动推进迭代器并从中一一提取值,只需调用next(pool)

>>> next(pool)
'a'
>>> next(pool)
'b'

1
您正在循环打印项目。我要退出循环然后再回来的是什么?(我想从我停下的地方开始)。
user443854 2014年

7
@ user443854用于pool.next()从周期中获取下一个项目
Jacob Krall

4
@ user443854 FWIW这是比我更好的答案。没有理由重新实现库函数!
Jacob Krall

5
pool.next()对我不起作用,仅对next(pool)有效。可能是因为Python 3?
fjsj 2015年

6
@fjsj是正确的,在Python 3上需要使用next(iterator)(BTW在Python 2.x上也可以正常工作,因此是应该使用的规范形式)。请参阅generator.next()在python 3.0中可见吗?以获得更深入的解释。相应地更新了我的答案。
卢卡斯·格拉夫

54

正确的答案是使用itertools.cycle。但是,让我们假设库函数不存在。您将如何实施?

使用发电机

def circular():
    while True:
        for connection in ['a', 'b', 'c']:
            yield connection

然后,您可以使用for语句进行无限迭代,也可以调用next()从生成器迭代器获取单个下一个值:

connections = circular()
next(connections) # 'a'
next(connections) # 'b'
next(connections) # 'c'
next(connections) # 'a'
next(connections) # 'b'
next(connections) # 'c'
next(connections) # 'a'
#....

真好!列表用尽后如何知道重新开始?
user443854 2014年

1
@ user443854 while True永远重复的手段
Jacob Krall

2
@juanchopanza:是的;itertools.cycle是一个更好的答案。这显示了如何编写相同的功能(如果itertools不可用的话:)
Jacob Krall,2014年

简单生成器还会像itertools.cycle这样保存每个元素的副本吗?还是简单的生成器会成为内存效率更高的设计?根据cycle文档Note, this member of the toolkit may require significant auxiliary storage (depending on the length of the iterable).
dthor

2
@dthor此生成器创建一个包含三个元素的列表并对其进行读写,然后销毁该列表并永久创建一个新列表。该文档的cycle含义是,可迭代输入list在生成器启动之前已转换为,因为iterable“仅对一组值有效”。
雅各布·克拉尔

9

或者您可以这样做:

conn = ['a', 'b', 'c', 'd', 'e', 'f']
conn_len = len(conn)
index = 0
while True:
    print(conn[index])
    index = (index + 1) % conn_len

永远打印abcdefab c ...


3

您可以使用append(pop())循环完成此操作:

l = ['a','b','c','d']
while 1:
    print l[0]
    l.append(l.pop(0))

for i in range()循环:

l = ['a','b','c','d']
ll = len(l)
while 1:
    for i in range(ll):
       print l[i]

或者简单地:

l = ['a','b','c','d']

while 1:
    for i in l:
       print i

所有这些打印:

>>>
a
b
c
d
a
b
c
d
...etc.

在这三个函数中,我倾向于使用append(pop())方法作为函数

servers = ['a','b','c','d']

def rotate_servers(servers):
    servers.append(servers.pop(0))
    return servers

while 1:
    servers = rotate_servers(servers)
    print servers[0]

支持这一点是因为它为我提供了一个完全不同的用例,在该用例中,我只是想遍历一个列表多次,而每次start元素都前进一个步骤。我的用例是在扑克游戏中遍历玩家,使发牌者每轮向前推动一名玩家前进。
约翰

2

您需要一个自定义迭代器-我将根据此答案改编迭代器。

from itertools import cycle

class ConnectionPool():
    def __init__(self, ...):
        # whatever is appropriate here to initilize
        # your data
        self.pool = cycle([blah, blah, etc])
    def __iter__(self):
        return self
    def __next__(self):
        for connection in self.pool:
            if connection.is_available:  # or however you spell it
                return connection

2

如果您希望循环n时间,请实施ncycles itertools配方

from itertools import chain, repeat


def ncycles(iterable, n):
    "Returns the sequence elements n times"
    return chain.from_iterable(repeat(tuple(iterable), n))


list(ncycles(["a", "b", "c"], 3))
# ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.