FAQ: Generators - Review

This community-built FAQ covers the “Review” exercise from the lesson “Generators”.

Paths and Courses
This exercise can be found in the following Codecademy content:

Learn Intermediate Python 3

FAQs on the exercise Review

There are currently no frequently asked questions associated with this exercise – that’s where you come in! You can contribute to this section by offering your own questions, answers, or clarifications on this exercise. Ask or answer a question by clicking reply (reply) below.

If you’ve had an “aha” moment about the concepts, formatting, syntax, or anything else with this exercise, consider sharing those insights! Teaching others and answering their questions is one of the best ways to learn and stay sharp.

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!
You can also find further discussion and get answers to your questions over in Language Help.

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head to Language Help and Tips and Resources. If you are wanting feedback or inspiration for a project, check out Projects.

Looking for motivation to keep learning? Join our wider discussions in Community

Learn more about how to use this guide.

Found a bug? Report it online, or post in Bug Reporting

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!

I’m really confused by this:

def graduation_countdown(days):
while days > 0:
days_left = yield days
if days_left != None:
days = days_left
else:
days -= 1

specifically the days = days_left part, and how days goes down by one if we send a value. If we send a value that isn’t None how would the else section execute?

I am struggling too on this logic.

What I deduced is since days is decremented, it means the if condition is not True, it means days left is None, it means the yield get the value from the send function when it is called, after that yield is used just for return the value.
check the value of days_left:

def graduation_countdown(days):
    while days > 0:
        days_left = yield days
        print(days_left)
        if days_left != None:
            days = days_left
        else:
            days -= 1

50
None
49
None
48
None

1 Like

I think you’ve got the logic down. The if clause, if days_left is not None, is only true on an iteration where something is sent to the generator (in which case we don’t want to immediately decrement that value anyway). So if we send in 20 days remaining then our next yield is 20 (returned immediately when .send is used), then the next normal value would be 19 and so on.

I think you can expect that the .send method is used very infrequently or not at all in this example so most of the time the else clause is used instead (decrement as per usual).

2 Likes

OK, so it helped me to remember that loops inside generators pause after each next or send call.

With that in mind, when we send a value, that value is set to the yield and returned immediately as our first day, which means that days_left != None is True because we sent it a value and now days = days_left. At this point the generator will pause and await either another send or a next call. If we just want to get the next value or yield counting down from the value we just set using our send, we would just use next. This means we are not sending a value, just retrieving the next value / yield, which means days_left != None is False. As a result, the else clause will be triggered and the days will decrement by 1. So long as we continue to use next for each subsequent iteration, the else clause will continue to execute until days > 0 is False.

Furthermore, if we were to use send again with a new value, then days_left != None is True and days would be set to this new value and the countdown would begin again from there with the next next call.

Hope that makes sense. :slight_smile:

1 Like

Isn’t this code right? The output is as expected…

def honors_generator(gpas):
  honors = [(3.9, summa), (3.7, magna), (3.5, cum_laude)]
  for gpa in gpas:
    for gpa_l, assign in honors:
      if gpa > gpa_l:
        yield from assign()

honors_it = honors_generator(gpas)
for honor_label in honors_it:
  print(honor_label)

Which produces

Summa Cum Laude
Magna Cum Laude
Cum Laude
Cum Laude

But it isn’t excepted…