Thursday Mornings With Python, Part 4

Thursday Mornings With Python, Part 4 

A black silhouette of a person standing on a black cliff, with a purple and green sky. Pink and purple text lists Susanna's Python topics covered today.

Continuing with iterators - Next

Awwww how cute - the next lesson also just happens to be on something called next. There is a method in iterators called next() and it can be used as next() or __next__(), and it works similarly to iter() and __iter__(). The moment I saw the title of the less I got it straight away. I don't want to spend too long on it. But what does it do under the hood? Basically, next in whatever form you choose, RETRIEVES THE ITERATOR'S NEXT VALUE. 

It will raise an exception called StopIteration when all items have ben iterated through. But then what happens - does the exception get handled? PYTHON HANDLES THE EXCEPTION StopIteration  BY STOPPING THE LOOP WITHOUT THROWING AN ERROR (during a for loop).

Iterators and For Loops

This literally just explains what is going on under the hood with for loops - then we can create our own custom iterators.
  • iter()
  • next()
  • and StopIteration

Custom Iterators 

  • the methods __iter__() and __next__() must be implemented for an object to be an iterator object
  • The implementation of these methods is called iterator protocol
  • "If we desire to create our own custom iterator class, we must implement iterator protocol". Which means that "we need to have a class that defines at miniumum the __iter__() and __next__() methods." 
  • And maybe more?
Custom classes are not iterable.

But we might have a class that needs the ability to iterate?! In that case we can define the __iter__() and __next__() methods for ourselves.  
class DreamsInventory:
    def __init__(self, dreamList):    
        self.all_dreams = dreamList
If we want to add to it we must define it more by implementing the iterator protocol by defining the __iter__() and __next__() methods.

We want to make the DreamInventory class iterable. Adding a class member within the __iter__() method called index will help us to keep track of the current position in the list that we're at. Very important: the __iter__() method returns itself since this class WILL BE AN ITERATOR OBJECT. Huh? I don't get this.
Okay I think I do now - we can use iter() to turn another object into an iterable - but it is usually just called on itself. Is this right please? Thanks. 

I'm gonna ask Chat GPT...

Chat GPT says:

  • When you call the __iter__() method, you're saying, "Give me an iterator to loop through."
  • By returning self, you're saying, "This object is the iterator."

  • Okay yes there I think I get it. We're saying - this specific instance of this class is the specific object that we want to loop over. It is saying - I am both the looped over object and the object that will do the looping.

    Remember we need to raise a StopIteration exception otherwise our code will error . That means we need to use an if/else statement (classic) to check for this condition.
    class DreamsInventory:
        def __init__(self, dreamList):    
            self.all_dreams = dreamList
    
        def __iter__(self):
          self.index = 0
          return self
        
        def __next__(self):
          if self.index < len(self.all_dreams):
            dream = "One of your dreams is to " + self.all_dreams[self.index]
            self.index += 1
            return dream
          else:
            raise StopIteration

    Python's Itertools: Built-in Iterators 

    🤔🤔

    Python's module named "itertools" provides the ability to create complex iterator manipulations.

    There are three categories of itertools iterators:
    • Infinite iterators
      • These will repeat an infinite number of times
      • They will not raise a StopIteration exception and will require some form of stop condition to exit from
    • Input-Dependent Iterators
      • They are terminated by the input iterable(s) sequence length. 
        • This is all so vague to me thanks and I need to see it to get it more so let's see thanks.
        • The smallest length iterable parameter of an input-dependent iterator will terminate the iterator. 
        • HUH?
    • Combinatoric Iterators
      • these are iterators that are COMBINATIONAL
      • mathematical functions are performed on input iterable(s).
    A diagram from the codecademy course illustrating the three different types of itertools iterators.

    What none of this makes any sense.

    Show me the code already haha. Also, you need to import these.

    Infinite Iterator: Count

    I mean, this feels a bit like a JavaScript while loop... which no-one ever uses and everybody dislikes or hates.

    Questions

    • When we do 

      def __iter__(self):
      self.count = 0
      return self
    then why do we return self? It made sense to me at first but then of course the Codecademy course confused me - anyway, thanks.
    • Chat GPT said something to me that was interesting like "I am both the object that is iterated over and the one that does the iterating" and I would like to understand this a bit better please. Thanks.

    • Why can't instances of Python classes just be iterable by default? Isn't that a bit dumb please? Thanks.

    • Could we maybe talk a bit more about the three types of iterators please? Thanks. Or do I not need to know them? Do I not need to care please? Thanks.

    • This is super interesting and can't wait to learn more - could see myself spending an hour or two on it over the weekend over it just because I'm dying to know.

    • Is an infinite iterator like a JavaScript while loop?

    Post Q+A Session

    I had a really lovely session as always.

    I get to ask questions and share what I have learned in the morning and really learn loads.

    It is so so so amazing.

    I was given a link to the Python documentation to read: https://docs.python.org/3/glossary.html#term-iterator

    OMG THIS IS SO SO BEAUTIFUL WOW. THIS IS SO SO SO SO BEAUTIFUL WOW

    "An object representing a stream of data." That is what an iterator is.

    "Iterators are required to have an __iter__() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterators are accepted." Wait what???! What does this mean please - thanks. 

    As always I will ask Chat GPT... 

    I'm afraid I still don't get it so I have asked my senior colleague, and if needs be I will ask around wider in the company.

    Chat GPT explanation of why an iterable returns itself
    If I understand then I will update this blog post but I am just hitting publish for now so that it is done. Thank you!!! 

    I think we finally made it click with the 

    def __iter__(self):
    self.count = 0
    return self

    thing.

    It's just basically like a variable reassignment thing. Wow.


    Comments

    Popular posts from this blog

    Hello World

    Yosemite

    Two Lines of Thought, Makes Me Wonder What I'm Missing