I'm writing this answer because the comments section seemed a little too constricting.
First of all, reading up about Iterators in python will clear up your confusion.
I'll try to explain anyways! :D
def batched(iterator, batch_size):
while True:
data = np.zeros(batch_size)
target = np.zeros(batch_size)
for index in range(batch_size):
data[index], target[index] = next(iterator)
yield data, target
batched is a generator/iterator function. The key here is yield. When the program flow hits yield, the function "returns" the values (data, target in our case). But the catch is, only when the function is called the next time, the flow continues from where it had yielded the last time. In our case, the next time the function is called, the loop starts atop.
Now, as you might be misguided by the while True: loop without a breaking condition, batched is not a blocking function call.
Also, do note that,
batches = batched(examples, params.batch_size)
is not a function call. You just get a pointer to the iterator when you execute the above line. The function runs only when it's iterated over!
For you, it's being done here:
for index, batch in enumerate(batches):
Here again, the for loop would fall into the infinite loop if the terminator condition is not handled within the loop. Meaning, the loop needs to be terminated manually with a break inside the for loop.