No overload variant of "next" matches argument type List[Scene]

Viewed 565

I get this mypy error No overload variant of "next" matches argument type List[Scene] when I am trying to check my following code.

class Scene:
    def __init__(self):
        self.a = None
    def something(self):
        self.a = 2

class Game:
    def __init__(self, scenes:List[Scene]) -> None:
        self.scenes = iter(scenes)
        self.current_scene = next(scenes)

How do I get rid of this? The error comes from the last line of the code. I have tried self.scenes:Iterator = iter(scenes) but even that does not help.

1 Answers

If you're trying to write a Python iterator, you need to provide certain "magic" dunder functions, such as __iter__() and __next__(). These functions are the ones called by those things that can iterate over a class.

For example, here's a class that returns all odd numbers in a range, much like range() returns all numbers in a range:

class odd_range(object):
    def __init__(self, first_one, last_plus_one):
        # Ensure start at first odd >= given start, and
        # store terminator for later checking.

        self.__curr = first_one
        if first_one % 2 == 0:
            self.__curr += 1

        self.__term = last_plus_one

    def __iter__(self):
        return self

    def __next__(self):
        # Terminate if range over, otherwise
        # return current, calculate next.

        if self.__curr >= self.__term:
            raise StopIteration()

        cur = self.__curr
        self.__curr += 2
        return cur

However, even if your List class provides that (and we can't tell for sure without the source), you may think that you are iterating over the list with the following code, but you are not:

def __init__(self, scenes:List[Scene]) -> None:
    self.scenes = iter(scenes)
    self.current_scene = next(scenes)

You create an iterator self.scenes but the thing you are calling next on is the original collection scenes passed in to __init__(), not the iterator itself. If you wanted to use the iterator, that would be:

self.current_scene = next(self.scenes)

Though you would be better off using a more descriptive name like self.scenes_iterator to better distinguish them.

Related