The objective of my assignment is to produce list elements indefinitely. So I did this:
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()
The solution has something like this:
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()
The output although is same in both the cases:
codewingx@CodeLair:~/repo/python$ python load_balancer.py
APP1
APP2
APP3
APP1
APP2
APP3
APP1
APP2
APP3
So how is generator function beneficial?
itertools.cycle()
The generator does not add anything useful here. I would try to avoid pop(0)
as it triggers a rebuild of the whole server list each time.
I would recommend itertools.cycle() :
from __future__ import print_function
from itertools import cycle
SERVERS = ['APP1', 'APP2', 'APP3']
servers = cycle(SERVERS)
for i in range(9):
print(next(servers))
Output:
APP1
APP2
APP3
APP1
APP2
APP3
APP1
APP2
APP3
Our wrapped in a function to match your usage:
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())
Output:
APP1
APP2
APP3
APP1
APP2
APP3
APP1
APP2
APP3
To make the point for a generator, a variation that takes advantage of its ability to store stet might more useful:
def gen():
index = 0
end = len(SERVERS)
while True:
yield SERVERS[index]
index += 1
if index >= end:
index = 0
While this illustrates nicely that you have state working with index
, the same can be achieved more easily with:
def gen():
while True:
for server in SERVERS:
yield server
g = gen()
def get_server():
return next(g)
This avoids modifying the list of SERVERS
. The result is the same:
for i in range(9):
print(get_server())
Output:
APP1
APP2
APP3
APP1
APP2
APP3
APP1
APP2
APP3
A simple generator function:
>>> def gen():
... print('start')
... yield 1
... print('after 1')
... yield 2
... print('after 2')
...
Make an instance:
>>> g = gen()
Use next
to get the next value returned by yield
:
>>> next(g)
start
1
Keep going:
>>> next(g)
after 1
2
Now it is exhausted:
>>> next(g)
after 2
StopIteration next(g)
You may think of cursor that moves along in the generator function. Every time you call next()
it moves to the next yield
. So putting the yield
in a while True
loop makes an infinite generator. As long as you don't call close()
on it, it gives you a new value with yield
. Also, you have state inside the generator. This means you can do things like incrementing counters between calls to next()
.
A list is its own generator in this context:
for i in SERVERS:
do_something_with_element(i)
If you want an infinite generator, @MikeMüller's itertools.cycle
is preferred for not-reinventing-the-wheel. If you must do your own:
def my_cycle(s):
while True:
for i in s:
yield i
but don't, it is less efficient and asks more of the code reader's memory.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.