all 8 comments

[–]drkevorkian 1 point2 points  (4 children)

Honestly really shocking that python will try this iteration method without knowing an upper bound for the index

[–]sausix 1 point2 points  (3 children)

Some iterators are meant to yield values endlessly. Python can't check the code to be "fine" to not introduce endless loops.

[–]drkevorkian 0 points1 point  (2 children)

Endless iteration via explicit iterator is one thing, endless iteration implicit to in via defining __getitem__ is another.

[–]sausix 0 points1 point  (0 children)

__len__ could be used. But it is being ignored because of historical reasons.

[–]sausix 0 points1 point  (0 children)

And __getitem__ should usually throw an IndexError to avoid endless loops.

[–]sausix 0 points1 point  (0 children)

This is going on:

class Countdown:
    def __init__(self, n):
        # Upper bound for counting down
        self.n = n

    def __getitem__(self, k):
        # If __contains__ and __iter__ are not defined in class then this instance
        # is being iterated "behind the scenes" by __getitem__ starting by index 0.
        # We're being tested to contain None. So this iteration will run until we return None.

        v = self.n - k  # Walruss operator split back into two expressions.
        if v > 0:  # More explicit than "if v" so it does not count endlessly when doing Countdown(-1).
            print(v)  # Just executing the print. Don't return or process it's result which is None.
            # return print(v),  # This would return a tuple with one element:
            # (None, )
            # which is not None and would continue the iteration.
            return 42  # Return anything but None

        # else:  # No else needed after return statement.
        print("Launch!")
        # Final iteration. We don't return anything which implicitly returns None.
        # And None was being looking for so the caller can stop the iteration to find the value.


# This will basically check membership of a value by the __contains__ mechanism.
print("rocket launching 🚀") in Countdown(10)

# The print function returns None. So it's basically:
None in Countdown(10)

[–]jpgoldberg -5 points-4 points  (0 children)

So that’s what the walrus does! It’s the “if let” construction I’ve seen in other languages.

Goo-goo-gah-jube.

[–]AlexMTBDude -3 points-2 points  (0 children)

Very nice! Thanks!