Python Forum
Iterator and/or generator help
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Iterator and/or generator help
#1
Hi All,
First time poster so please excuse noob mistakes.
I am using Micropython to program a microcontroller (an ESP32 for this project) and one of the things I need to do is iterate through a list of fixed values repeatedly, that is restart at the first item after the last item has been returned. My knowledge of Python is not deep, it's pretty basic so I'm currently doing this.
chan_order = (5, 9, 2, 14, 3, 7, 13, 6, 12, 4, 8, 11, 1, 10)

n = 0
next_chan = 5

def cb(t):
    global n
    n = (n + 1) % 14
    next_chan = chan_order[n]
    do something with next_chan
    ...
Function cb is a callback routine driven by a timer, so it's run continuously, 100 times a second.

This works, but in my quest to learn more about Python I started exploring the murky world of iterators and generators, as it seemed to me that I could then just do something like "next_chan = somefunc.next()", but the stumbling block I keep tripping over is getting the iterator to restart at the beginning when it hits the last item in the list. I found in Python there is a library called "itertools", which has a "cycle" function in it that looks like it would do what I want to do, but unfortunately itertools doesn't exist in Micropython.

Is there a way I can use an iterator (or a generator) to do this? Or is it overcomplicating the solution.

All advice gratefully received.
Smile
Reply
#2
Well, I think you don't need generators for small amounts of data.

I think for your purpose, lists or tuples are most suited

Here a link to the docs for Python lists

# tuples are immutable, theoretically
chan_order = (5, 9, 2, 14, 3, 7, 13, 6, 12, 4, 8, 11, 1, 10)
type(chan_order) # <class 'tuple'>
for c in chan_order:
    print(c)

# generators are used up then stop
chan_gen = (x for x in chan_order)
type(chan_gen) # <class 'generator'>
# see the numbers
for g in chan_gen:
    print(g)
    
# try that again, get nothing
for g in chan_gen:
    print(g)

# list is most useful, can be changed, can't be used up
chan_list = list(chan_order) # or do it like this: chan_list = [x for x in chan_order]
chan_list # [5, 9, 2, 14, 3, 7, 13, 6, 12, 4, 8, 11, 1, 10]
type(chan_list) # <class 'list'>

chan_range = range(1,15)
type(chan_range) # <class 'range'>
for i in chan_range:
    print(i)
Info:

Quote:There are four collection data types in the Python programming language:

List is a collection which is ordered and changeable. Allows duplicate members.
Tuple is a collection which is ordered and unchangeable. Allows duplicate members.
Set is a collection which is unordered, unchangeable*, and unindexed. No duplicate members.
Dictionary is a collection which is ordered** and changeable. No duplicate members.

A dictionary has key: value pairs. A dictionary can have duplicate values, but not duplicate keys.
Reply
#3
Hi and welcome to python-forum.io!

I don't know which features micropython lacks, but you could try this
chan_order = (5, 9, 2, 14, 3, 7, 13, 6, 12, 4, 8, 11, 1, 10)


def cycle_tuple(t: tuple):
    while t:
        for c in t:
            yield c


chan_cycle = cycle_tuple(chan_order)

if __name__ == "__main__":
    for i in range(30):
        c = next(chan_cycle)
        print(c, end=" ")
    print()
My output:
Output:
5 9 2 14 3 7 13 6 12 4 8 11 1 10 5 9 2 14 3 7 13 6 12 4 8 11 1 10 5 9
« We can solve any problem by introducing an extra level of indirection »
Reply
#4
Hi,

if you take a look in the docs of CPython for the itertools module, you will find code which does roughly the same like itertools.cycle, implemented with the core functionality of Python only: https://docs.python.org/3/library/iterto...ools.cycle

Regards, noisefloor
bowlofred likes this post
Reply
#5
@Gribouillis

You are the expert here, not me, but don't you think an endless while loop is, well, not recommended?
Reply
#6
The OP has is a sequence that repeats endlessly.
Reply
#7
Well, I just think, if the OP wants to log some data which occurs 100 times a second, the log file will get quite big quite quickly.

There must be a STOP condition, n'est pas?
Reply
#8
(Dec-05-2025, 08:35 AM)Pedroski55 Wrote: Well, I just think, if the OP wants to log some data which occurs 100 times a second, the log file will get quite big quite quickly.

There must be a STOP condition, n'est pas?
The while loop inside the generator function does not need a stop condition because it is stopped every time by the yield statement. The loop is driven by the client code which determines how many times it calls the next() function. Every external call to next(chan_cycle) runs the internal loop once. The client code has all the responsibility.

A nice feature of generator objects is that they allow us to work conceptually with infinite sequences, although every execution of the program will consume only a finite number of elements.
« We can solve any problem by introducing an extra level of indirection »
Reply
#9
(Dec-05-2025, 08:35 AM)Pedroski55 Wrote: There must be a STOP condition, n'est pas?
No, there must be no stop condition. At least not for the TS, as the question is about an endless generator. Seems to be useful for him / her. There can be a stop condition, but it is neither mandatory nor enforced by Python. Remember that an endless generator is technically _not_ the same like an infinite loop.

Regards, noisefloor
Reply
#10
This is probably what you're looking for:

chan_order = (5, 9, 2, 14, 3, 7, 13, 6, 12, 4, 8, 11, 1, 10)

def chan_cycle():
    while True:
        for ch in chan_order:
            yield ch

chan_iter = chan_cycle()
Then in your callback:

def cb(t):
    next_chan = next(chan_iter)
    # do something with next_chan
That's it.

When it hits the end of the tuple, it just starts again automatically.
our gaming project:- TAG game
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Why not use len(alist) in an iterator? Pedroski55 5 2,317 Jun-27-2024, 02:49 PM
Last Post: snippsat
  prime numbers with iterator and generator cametan_001 8 5,085 Dec-17-2022, 02:41 PM
Last Post: cametan_001
  resetting an iterator to full Skaperen 7 13,766 Feb-20-2022, 11:11 PM
Last Post: Skaperen
  popping an iterator Skaperen 11 6,918 Oct-03-2021, 05:08 PM
Last Post: Skaperen
  q re glob.iglob iterator and close jimr 2 4,038 Aug-23-2021, 10:14 PM
Last Post: perfringo
  Problem with an iterator grimm1111 9 7,867 Feb-06-2021, 09:22 PM
Last Post: grimm1111
  Multi-class iterator Pedroski55 2 3,739 Jan-02-2021, 12:29 AM
Last Post: Pedroski55
  is a str object a valid iterator? Skaperen 6 8,599 Jan-27-2020, 08:44 PM
Last Post: Skaperen
  discard one from an iterator Skaperen 1 3,070 Dec-29-2019, 11:02 PM
Last Post: ichabod801
  looking for a sprcil iterator Skaperen 7 5,998 Jun-13-2019, 01:40 AM
Last Post: Clunk_Head

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020