3

I'm trying to create a simple function that allows a user to input basic information that will change the values of a datetime object, and I'd like to find a way to make it as clean as possible by using a variable as a keyword. This can easily be done a different way, but I figured it'd be useful to know how to replace pre-set keywords.

The datetime object has a .replace() method that takes any time value as a keyword:

datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]])

But I want to allow the user to specify how much of which kind of time (e.g., 2 days; 4 hours; 1 month).

I'm trying to replace any of the above keywords up to "minute" with whatever the user inputs, which is stored in the time_type variable, but I get "TypeError: 'time_type' is an invalid keyword argument for this function".

    start_time = datetime.datetime(2016, 09, 16, 15, 30)

    def change_time(integer, time_string):
        time_type = time_string.replace("s","")  # de-pluralizes input
        new_time = getattr(start_time, time_type) + integer
        print(start_time.replace(time_type=new_time))

    change_time(2, "days")

This should print the new start_time, which is (2016, 09, 18, 15, 30), but I just get an error.

smc5293
  • 33
  • 3
  • Build a dictionary of keyword arguments, then use `**` to unpack it (see http://stackoverflow.com/q/36901/3001761). – jonrsharpe Sep 16 '16 at 20:09

3 Answers3

3

Python allows you to store data in a dictionary and finally unpack them as keyword arguments to different functions.

For the thing that you want to do, best way to accomplish this is to use kwargs.

replacement_info = {'day': 2, 'month': 9, ...}

new_time = start_time.replace(**replacement_info)

Note the difference with what you've done. Passing time_type directly to replace, would result in replace being called with the time_type parameter, set to 2, which is undefined (since it's not in the list of accepted arguments for replace)

Instead you have to pass it like **{time_type: 2} to the replace function, this way, replace will receive the interpreted value for time_type, namely day, as the input.

So you need to change

print(start_time.replace(time_type=new_time))

to

print(start_time.replace(**{time_type:new_time})
SpiXel
  • 4,338
  • 1
  • 29
  • 45
1

You cannot replace keyword arguments on a function you did not write. When calling a function like:

f(a=b)

The value of a is not sent as an argument to f. Instead, the value of b is sent and that value is set to the argument a in f's argument list definition. If f does not have an argument a defined (as datetime.replace does not have a time_type argument defined), you will get an invalid keyword argument exception.

As others have said, to pass dynamic keyword arguments to a function use the **kwargs notation.

Craig Burgler
  • 1,749
  • 10
  • 19
0

Change your last line to something like this:

year = start_time.year
month = start_time.month
day = start_time.day
hour = start_time.hour
minute = start_time.minute
second = start_time.second
microsecond = start_time.microsecond
exec(time_type + '='+str(new_time))
print(start_time.replace(year, month, day, hour, minute, second, microsecond)
Jeff
  • 2,040
  • 3
  • 18
  • 19