Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Functional Python The Lambda Lambada Recursion

Finish the prereqs function so that it recursively finds all of the course titles in courses.

I'm getting this as an output which I believe is correct:

{'Python Basics', 'Setting Up a Local Python Environment', 'Python Collections', 'Flask Basics', 'Object-Oriented Python'}

courses.py
courses = {'count': 2,
           'title': 'Django Basics',
           'prereqs': [{'count': 3,
                     'title': 'Object-Oriented Python',
                     'prereqs': [{'count': 1,
                               'title': 'Python Collections',
                               'prereqs': [{'count':0,
                                         'title': 'Python Basics',
                                         'prereqs': []}]},
                              {'count': 0,
                               'title': 'Python Basics',
                               'prereqs': []},
                              {'count': 0,
                               'title': 'Setting Up a Local Python Environment',
                               'prereqs': []}]},
                     {'count': 0,
                      'title': 'Flask Basics',
                      'prereqs': []}]}


def prereqs(data, pres=None):
    pres = pres or set()
    if (data['prereqs']):
        for course in data['prereqs']:
            pres.add(course['title'])
        data = data['prereqs'][0]
        prereqs(data, pres)
    else:
        return (pres)

8 Answers

Ryan Ruscett
Ryan Ruscett
23,309 Points

Hola,

You are super super close lol.

Look at your code. The if statement in particular.

Not all the titles have prereqs. So you are exiting with a return statement if one does not.

Expected output vs your output.

set(['Flask Basics', 'Setting Up a Local Python Environment', 'Python Basics', 'Object-Oriented Python', 'Python Collections'])

NOT

{'Python Basics', 'Setting Up a Local Python Environment', 'Python Collections', 'Flask Basics', 'Object-Oriented Python'}

So you are missing a few courses.

Simple fix, just take your return statement out of the if statement and remove the else. This way it runs until completion. Than returns the full set.

def prereqs(data, pres=None):
    pres = pres or set()
    if (data['prereqs']):
        for course in data['prereqs']:
            pres.add(course['title'])
        data = data['prereqs'][0]
        prereqs(data, pres)

    return (pres)

Does this help? Let me know if it's still confusing but you are right on track!

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,457 Points

Ira Bradley, glad you were able to figure it out. I was also initially stumped on this one until I realized the desired solution is only the prerequisites and does not include the top-level course title. That is, the top course isn't a prerequisite of itself. Solution contains 5 courses.

Here is an alternative solution that might be more easily understood:

def prereqs(data, pres=None):
    pres = pres or set()
    # for each prereq in this courses' prereqs...
    for prereq in data['prereqs']:
        # add title of this prereq course, then...
        pres.add(prereq['title'])
        # use recursive call to find further prerequisites of this
        # course, if any
        prereqs(prereq, pres)
    # return current 
    return pres
Ryan Ruscett
Ryan Ruscett
23,309 Points

Hey,

Yeah this wont be easy to explain so grab a beer and let's ponder this lol.

What is happening is that your code is building fine. EXCEPT you are calling a function in a function. What this means is that when the return statement is hit. It's ok, everything looks find. But since you called the function in a function, it actually calls the function one more time. Not the entire function, but the inner function. The inner function is the function that calls it'self.

def prereqs(data, pres=None):    <---------OUTER FUNCTION
    pres = pres or set()
    if (data['prereqs']):
        for course in data['prereqs']:
            pres.add(course['title'])
        data = data['prereqs'][0]
        prereqs(data, pres)    <---------------------INNER FUNCTION
    else:
        return (pres)

What this means is that the function is in two places, and essentially, when it returns data. It takes the most inner portion of it'self.

Once you hit the return statement, since you ran a function in a function. The return statement kicks the process flow to the most inner function. Than that is the function that returns it data up to the higher version or outer version of it'self. Which ultimately is the function we except to get our data from.

Like this

A = prereqs(courses)

I would expect the function to return to A the value of pres. But it doesn't. The outer function runs. Calls the inner which in turn calls the outer. When the else statement runs. pres is returned but it's returned to the function. Which is the inner function. Not the outter function. Since the inner function is what called the outer function that produced the return statement.

When the outer Function is ran it runs. But when the inner function calls the outer function. And the if statement doesn't run the inner fucntion because it returns a false. The else statement runs for the outter function, but the last funciton to call the outer function was the inner function. So the data is returned to the inner function. This cause what is known as func_closure. Must close the inner function, but the innerfunction didn't really do anything except call the outter function. So the inner functions not going to return our list to A because our list was already returned to the inner Function. SO what gets put into A is actually a NoneType: None from the inner function.

Does this make any sense lol. It's a tuff topic I will break it down more if you need. lol

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,457 Points

Ira Bradley, glad you were able to figure it out. I was also initially stumped on this one until I realized the desired solution is only the prerequisites and does not include the top-level course title. That is, the top course isn't a prerequisite of itself. Solution contains 5 courses.

Here is an alternative solution that might be more easily understood:

def prereqs(data, pres=None):
    pres = pres or set()
    # for each prereq in this courses' prereqs...
    for prereq in data['prereqs']:
        # add title of this prereq course, then...
        pres.add(prereq['title'])
        # use recursive call to find further prerequisites of this
        # course, if any
        prereqs(prereq, pres)
    # return current 
    return pres
Tyler Taylor
Tyler Taylor
17,939 Points

I feel like this one went right over my head. Like where did all of these new things come from? or set()? I don't remember that in any of the lessons. Oh well... Your answer helped clear it up at least a little bit.

Hi Ryan,

Thanks for the help. I'm still confused however. My return object has the same titles in it that yours does including 'Python Collections'. We both have 5 titles.

As far as I can tell there is no difference between our functions. Removing the else statement doesn't change when the return gets run. I must be missing something but am still not seeing it.

Ryan Ruscett
Ryan Ruscett
23,309 Points

When I run your code in the challenge I get a "try again." When I run it in my IDE I get "None" for the list.

When I remove the else and put the return statement under the if statment. I pass the challenge, and my IDE it shows me set(['Flask Basics', 'Setting Up a Local Python Environment', 'Python Basics', 'Object-Oriented Python', 'Python Collections'])

Where are you getting your output from? Is that coming from or from an interpreter?

def prereqs(data, pres=None):
    pres = pres or set()
    if (data['prereqs']):
        [pres.add(course['title']) for course in data['prereqs'] ]
        data = data['prereqs'][0]
        prereqs(data, pres)
    return (pres)

I ended up passing with the above code. I still don't understand fully while the else: was screwing it up? My thinking is that when the if statement is true we enter that code block and then recursively call prereqs. When the if statement isn't true we hit the return. I don't see how removing the 'else' changes the control flow but it obviously does.

I'd really appreciate if you can explain that one to me.

Ryan,

Thanks for this explanation. I "knew" this but somehow forgot it temporarily. I was struggling to figure out why the return wasn't kicking us out of the function entirely but now I understand.

Thanks again. I officially owe you a beer :)

Sebastian Röder
Sebastian Röder
13,878 Points

As an alternative, you could implement the function with a list comprehension:

def prereqs(data, pres=None):
    pres = pres or set()

    [(pres.add(course['title']), prereqs(course, pres)) for course in data['prereqs'] if data['count'] > 0]

    return pres