我的任务目标是无限期地生成列表元素。 所以我这样做了:
SERVERS = ['APP1', 'APP2', 'APP3']
#SERVERS = ['APP1', 'APP2', 'APP3', 'APP4', 'APP5', 'APP6']
length = len(SERVERS)
def get_server():
current_server = SERVERS.pop(0)
SERVERS.append(current_server)
return current_server
if __name__ == '__main__':
for i in range(9):
print get_server()
解决方案有这样的事情:
SERVERS = ['APP1', 'APP2', 'APP3']
#SERVERS = ['APP1', 'APP2', 'APP3', 'APP4', 'APP5', 'APP6']
def get_server():
def f():
while True:
i = SERVERS.pop(0)
SERVERS.append(i)
yield i
return next(f())
if __name__ == '__main__':
for i in range(9):
print get_server()
输出虽然在两种情况下都相同:
codewingx@CodeLair:~/repo/python$ python load_balancer.py
APP1
APP2
APP3
APP1
APP2
APP3
APP1
APP2
APP3
那么发电机功能如何有益呢?
答案 0 :(得分:2)
itertools.cycle()
生成器不会在这里添加任何有用的东西。我会尽量避免使用pop(0)
,因为它每次都会触发整个服务器列表的重建。
from __future__ import print_function
from itertools import cycle
SERVERS = ['APP1', 'APP2', 'APP3']
servers = cycle(SERVERS)
for i in range(9):
print(next(servers))
输出:
APP1
APP2
APP3
APP1
APP2
APP3
APP1
APP2
APP3
我们的功能与您的用法相匹配:
def make_get_server():
servers = cycle(SERVERS)
def get_server():
return next(servers)
return get_server
get_server = make_get_server()
for i in range(9):
print(get_server())
输出:
APP1
APP2
APP3
APP1
APP2
APP3
APP1
APP2
APP3
为了说明生成器,利用其存储stet的能力的变体可能更有用:
def gen():
index = 0
end = len(SERVERS)
while True:
yield SERVERS[index]
index += 1
if index >= end:
index = 0
虽然这很好地说明了您正在使用index
状态,但可以通过以下方式更轻松地实现:
def gen():
while True:
for server in SERVERS:
yield server
g = gen()
def get_server():
return next(g)
这可以避免修改SERVERS
列表。结果是一样的:
for i in range(9):
print(get_server())
输出:
APP1
APP2
APP3
APP1
APP2
APP3
APP1
APP2
APP3
一个简单的生成器函数:
>>> def gen():
... print('start')
... yield 1
... print('after 1')
... yield 2
... print('after 2')
...
制作一个实例:
>>> g = gen()
使用next
获取yield
返回的下一个值:
>>> next(g)
start
1
继续前进:
>>> next(g)
after 1
2
现在已经筋疲力尽了:
>>> next(g)
after 2
StopIteration next(g)
您可能会想到在生成器函数中移动的光标。每当您拨打next()
时,它都会移至下一个yield
。因此将yield
置于while True
循环中会产生无限生成器。只要您不在其上调用close()
,它就会为您提供yield
的新值。此外,您在发电机内部有状态。这意味着您可以执行诸如在next()
的调用之间递增计数器之类的事情。
答案 1 :(得分:1)
在此上下文中,列表是它自己的生成器:
for i in SERVERS:
do_something_with_element(i)
如果你想要一个无限的发电机,@MikeMüller的itertools.cycle
是不重新发明轮子的首选。如果你必须自己做:
def my_cycle(s):
while True:
for i in s:
yield i
但不要,效率较低,并要求更多代码阅读器的内存。