Iterators are a common pattern in python. A trivial example is:
example = iter(("apple", "banana", "cherry"))
next(example)
(yes, of course, one does not need to treat this specific case as an iterator, it is just a minimal example)
How does one effectively work with iterators using the ExternalEvaluate / ExternalFunction in Mathematica?
Some strategies that do not work:
Strategy 1: ExternalObject
The tuple iterator gets returned as an ExternalObject, but then there is a type conversion error when sending it back to python to apply the next() function to it:
(* create a python session *)
session = StartExternalSession["Python"];
(* define the iterator, returning a ExternalObject *)
ex = ExternalEvaluate[session, "iter((\"apple\", \"banana\", \"cherry\"))"]
(* define the next function *)
next = ExternalFunction[session, "next"];
(* but...applying the next function returns an error *)
next[ex]
(* Error Message: WLFunction' object is not an iterator *)
Strategy 2: PythonObject
The PythonObject resource function seems like it should help. Iterators define a __next()__ method that we should be able to call, but this does not seem to work:
(* define the PythonObject *)
ex2 = ResourceFunction["PythonObject"]["iter((\"apple\", \"banana\", \"cherry\"))"]
(* ex2["__next__"[]] *)
(* Failure: Message: name __next__ is not defined *)
(* ex2["next"[]] *)
(* Failure: Message: tuple_iterator has no attribute `next` *)