0

I was trying to make my custom class iterable by defining the __iter__ and __next__ methods. However, I want it to loop over different values under different conditions. So, I am using iter() with a yield statement when the fov_list (a list which specifies the index of subset of data to read) is available otherwise it I want it to loop through the whole data using __iter__ and __next__ until StopIteration exception is raised. Although, I have managed to fix the issue using a different approach. I was wondering if someone would help me understand why the __next_() method is not getting called when the conditions are True, that is, fov_list is not available.

class MERFISH_tools():

    def __init__(self):
        self.fov_list = []
        FOV_list_path = os.path.join(os.path.dirname(os.path.dirname(config.get("merlin_folder"))),"analysis_parameters","fov_list","fov_list.txt")
        if os.path.exists(FOV_list_path):
            with open(FOV_list_path) as f:
                self.fov_list = [int(fov.strip() for fov in f.readlines()]


    def __iter__(self):
        if len(self.fov_list) == 0:
           self.i = 0
           return self
        else:
           for fov in self.fov_list:
               yield fov,self[fov]

    def __next__(self) -> tuple:
        i = self.i
        self.i +=1
        if self.i > self.positions.positions.shape[0]:
            raise StopIteration
        return i,self[i]

I was expecting __next__ method to be called when __iter__ returns instance of the class. Does the use of yield statement affect the function of __next__?

Matthias
  • 12,873
  • 6
  • 42
  • 48
  • 2
    your `__iter__` method should **simply `return self`** always. What you've implemented is completely broken. – juanpa.arrivillaga Jul 14 '23 at 22:51
  • "I was trying to make my custom class iterable by defining the iter and next methods." That is wrong. To make a class *iterable*, you need to implement **only `__iter__`**, which will return *an iterator*. That iterator, should implement both `__iter__` (which should **only** `return self`), and `__next__`. – juanpa.arrivillaga Jul 14 '23 at 22:52
  • And yes, the use of `yield` makes your function a generator function. It **never** returns an instance of the class, it **always** returns a generator object. In the case where `if len(self.fov_list) == 0:`, then the generator *terminates* (which is what `return` does in a generator function), raising a `StopIteration` error (which contains the `return` value, btw) – juanpa.arrivillaga Jul 14 '23 at 22:53
  • @juanpa.arrivillaga thanks for commenting, could you please explain more so that I understand why such implementation is not appropriate? – Bereket Berackey Jul 14 '23 at 22:55
  • So, you need to understand 1) the iterator protocl 2) how generators work with `return`. I'm going to close this as a duplicate, because I think they explain these two things – juanpa.arrivillaga Jul 14 '23 at 22:58
  • He did explain. `__iter__` gets called once and is expected to return an iterator. Because you used `yield`, that CHANGES your function so that `return` doesn't return, it raises an exception. – Tim Roberts Jul 14 '23 at 23:00
  • [Here is a link to the offical docs about the iterator protocol](https://docs.python.org/3/library/stdtypes.html#typeiter), unfortunately, it is a bit terse. – juanpa.arrivillaga Jul 14 '23 at 23:02
  • 1
    @juanpa.arrivillaga thank you so much for the explains. So, if I understand correctly. whenever there is a {yield} statement inside a function, the function becomes a generator and for this reason the return statement 'return self' within '_iter_' was just raising the 'StopIteration' instead of returning the instance of the class. – Bereket Berackey Jul 14 '23 at 23:12
  • Yes, precisely. Also make sure to read the [answer](https://stackoverflow.com/a/45685692/5014455) in the other duplicate that I wrote, I explain how you would normally make a class iterable, that is, by writing a seperate iterator class, and how using a generator makes it much easier – juanpa.arrivillaga Jul 14 '23 at 23:15
  • I see thank you! I will also read the docs – Bereket Berackey Jul 14 '23 at 23:17

0 Answers0