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

John Forbes
John Forbes
10,879 Points

Why won't the timedelta function take a variable as a keyword?

When I run the code below it gives me this response, Bummer! 'the_string' is an invalid keyword argument for this function. I think I know how to fix it but just more of a general question as to why this is happening.

time_machine.py
import datetime

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

# Remember, you can't set "years" on a timedelta!
# Consider a year to be 365 days.
def time_machine(length_time, the_string):
  if(the_string == 'years'):
    return starter + datetime.timedelta(days=(length_time * 365))
  else:
    return starter + datetime.timedelta(the_string=length_time)


## Example
# time_machine(5, "minutes") => datetime(2015, 10, 21, 16, 34)

2 Answers

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,441 Points

It's a syntax issue. A keyword in an argument list to a function cannot be a variable or an expression.

You can construct a dict to use as a kwargs argument:

return starter + datetime.timedelta(**{the_string: length_time})

Chris two quick questions based on:

def time_machine(length_time, the_string):
    if(the_string == 'years'): return starter + datetime.timedelta(days=(length_time * 365))
    else: return starter + datetime.timedelta(**{the_string: length_time})      

1. why does this work:

if(the_string == 'years'): return starter + datetime.timedelta(days=(length_time * 365))

and this not

else: return starter + datetime.timedelta(the_string = length_time)     

is it because (the_string = length_time) is evaluated as an expression?

2. When you unpack the dictionary, how does python know to evaluate the datetime function with an "=" sign?

 return starter + datetime.timedelta(**{the_string: length_time})   

so for ex. with "weeks" and 5, how does it know to evaluate this as (where does the "=" sign come from)?

 return starter + datetime.timedelta(weeks = 5) 

Thanks much Dan

[MOD: added ```python formatting -cf]

Chris Freeman
Chris Freeman
Treehouse Moderator 68,441 Points

daniel steinberg, For 1, keyword names are not interpreted. They are parsed as literal strings. In the first case, β€œdays” is the keyword. In the second β€œthe_string” is the keyword which will be rejected by timedelta as an invalid keyword.

For 2, the magic is in the packing/unpacking operator **. When ** is used on a dictionary it converts the dict key/value pairs into keyword/argument pairs. This is where the equals sign is created.

# So, this
**{the_string: length_time}
# becomes this
(value_of_the_string=length_time)

For example:

def function(**dict_packed_kw_args):
    for key, value in dict_packed_kw_args.items():
        print(type(key), key, type(value), value)

var1 = 'days'
value1 = 10

function(**{var1: value1})

# output
# <class β€˜str’> days <class β€˜int’> 10

[MOD: added ```python formatting -cf]

Post back if you need more help. Good luck!!!

def time_machine(integer, the_string): if(the_string == 'years'): return starter + datetime.timedelta(days=(length_time * 365)) else: return starter + datetime.timedelta(**{the_string: integer})