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 Dates and Times in Python (2014) Let's Build a Timed Quiz App Harder Time Machine

David Sampimon
David Sampimon
12,026 Points

Why does this work? (Harder time machine code challenge)

I got stuck on this code challenge due to the keyword argument being used in timedelta and having to pass in a variable to make it work.

After searching the community forum I found the solution to pass in a dictionary and unpacking it with double asterix in the return statement. This passes the code challenge, but I do not understand what is happening. I read the python docs regarding keyword arguments, but am still puzzled: Why is for example: datetime.timedelta**{6 : 'hours'} understood as datetime.timedelta(hours=6)? in the last line?

Code:

import datetime

starter = datetime.datetime(2015, 10, 21, 16, 29)

def time_machine(time_amount, time_metric):
    if time_metric == 'years':
        # Ensure years are converted to days
        return time_machine(time_amount * 365, 'days')

    return starter + datetime.timedelta(**{time_metric: time_amount})

2 Answers

Jeff Muday
MOD
Jeff Muday
Treehouse Moderator 28,716 Points

The ** in front of a dictionary means to use the dictionary as the keyword arguments. This is a "clever" way of coding the question. I probably wouldn't write it this way since it violates the spirit of PEP 20.

https://peps.python.org/pep-0020/

But!! writing it this way saves quite a bit of typing and additional conditional branching.

I feel it can be written more simply and clear using the keyword arguments like below... The choice is yours to make!

def time_machine(time_amount, time_metric):
    if time_metric == 'minutes':
        time_delta = datetime.timedelta(minutes=time_amount)
    elif time_metric == 'hours':
        time_delta = datetime.timedelta(hours=time_amount)
    elif time_metric == 'days':
        time_delta = datetime.timedelta(days=time_amount)
    elif time_metric == 'years':
        time_delta = datetime.timedelta(days=time_amount*365)
    else:
        raise ValueError("time_machine() requires time_metric be minutes, hours, days, or years")

    return starter + time_delta
David Sampimon
David Sampimon
12,026 Points

Thank you Jeff!

I wasn't trying to be clever, I thought the answer was 'looking' for this approach. But then again, I am Dutch so maybe that gives me a bit of an excuses regarding the spirit of PEP20.

Jeff Muday
MOD
Jeff Muday
Treehouse Moderator 28,716 Points

I am praising you for brevity! Good job!

Although the course is geared toward beginners who would understand the "explicit" parameters of the way that I wrote the code.

The Challenge was written in a way that was "reversed" from what you would expect.

The dictionary would be {'hours' : 6} which would then be unpacked to hours=6 with the ** operator.

Enjoy your Python journey! GuidoVan Rossum (inventor of Python) is your fellow countryman, so you are well on your way to mastery!