【发布时间】:2021-04-11 06:59:16
【问题描述】:
我需要遍历一个循环列表,可能多次,每次都从最后访问的项目开始。
用例是一个连接池。客户端请求连接,迭代器检查指向的连接是否可用并返回,否则循环直到找到可用的连接。
有没有一种简洁的方法可以在 Python 中做到这一点?
【问题讨论】:
我需要遍历一个循环列表,可能多次,每次都从最后访问的项目开始。
用例是一个连接池。客户端请求连接,迭代器检查指向的连接是否可用并返回,否则循环直到找到可用的连接。
有没有一种简洁的方法可以在 Python 中做到这一点?
【问题讨论】:
正确答案是使用itertools.cycle。但是,让我们假设库函数不存在。你将如何实现它?
使用generator:
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'
#....
【讨论】:
while True 表示永远重复
itertools.cycle 是一个更好的答案。这显示了如果 itertools 不可用,您如何编写相同的功能:)
itertools.cycle 一样保存每个元素的副本?或者简单的生成器会是更节省内存的设计吗?根据cycle docs:Note, this member of the toolkit may require significant auxiliary storage (depending on the length of the iterable).
cycle 的文档暗示输入可迭代在其生成器启动之前转换为 list,因为 iterable 仅“适用于通过一组值”。
使用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'
【讨论】:
pool.next() 从循环中获取单个下一项
next(iterator) (顺便说一句,它在 Python 2.x 上也可以正常工作,因此是应该使用的规范形式)。有关更深入的解释,请参阅Is generator.next() visible in python 3.0?。相应地更新了我的答案。
您需要一个自定义迭代器——我将从this answer 改编迭代器。
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
【讨论】:
或者你可以这样做:
conn = ['a', 'b', 'c', 'd', 'e', 'f']
conn_len = len(conn)
index = 0
while True:
print(conn[index])
index = (index + 1) % conn_len
永远打印 a b c d e f a b c...
【讨论】:
您可以使用append(pop()) 循环来完成此操作:
l = ['a','b','c','d']
while True:
print l[0]
l.append(l.pop(0))
或for i in range()循环:
l = ['a','b','c','d']
ll = len(l)
while True:
for i in range(ll):
print l[i]
或者简单地说:
l = ['a','b','c','d']
while True:
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 True:
servers = rotate_servers(servers)
print servers[0]
【讨论】:
如果您希望循环 n 次,请实现 ncycles itertools recipe:
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']
【讨论】:
为了避免无限循环,我使用数组长度进行迭代,直到列表大小为两倍。您可以实现自己的前置条件。想法是避免无限循环。
#Implement Circular Linked List
from itertools import cycle
list=[1,2,3,4,5]
lstlength=len(list)*2
print(lstlength)
pool=cycle(list)
i=0
#To avoid infinite loop break when you have iterated twice size of the list
for items in pool:
print(items)
if i >lstlength:
break
i += 1
【讨论】: