Reputation: 2096
I would like to use a default parameter that is initialized when you call the function so its a different default parameter each time you call it. To illustrate what I'm asking say you want a time diff function that defaults to the current time if 2nd time is not supplied:
normally you do something like this.
def tdiff(target_time, curr_time=None):
if curr_time == None:
curr_time = datetime.datetime.now()
return curr_time - target_time
but it would be nicer to get rid of the if statement. Can this be done with lambda ? (Something like this)
def tdiff(target_time, curr_time= lambda : datetime.now() ):
return curr_time - target_time
Edit: I understand lambda will not work. Will any other method work?
Upvotes: 7
Views: 5700
Reputation: 2096
Thank you for your answers and to clarify I'm interested in any method not just lambda. So i looked at properties to see if that could work...
I created this to try it out.
import datetime
class DefaultParams():
@property
def curr_time( self ):
return datetime.datetime.now()
when you access the property defaults.curr_time
run it it yields the current time without being callable
>>> defaults = DefaultParams()
>>> defaults.curr_time
datetime.datetime(2018, 6, 2, 10, 49, 16, 38295)
>>> defaults.curr_time
datetime.datetime(2018, 6, 2, 10, 49, 17, 211985)
So i pluged that in and printed out the curr_time when you call tdiff
def tdiff(target_time, curr_time= defaults.curr_time ):
print(curr_time)
return curr_time - target_time
But when i run that it shows the curr_time reaming static @ 10:48:58.675151.
>>> tdiff(datetime.datetime.now())
2018-06-02 10:48:58.675151
datetime.timedelta(-1, 85430, 433255)
>>> tdiff(datetime.datetime.now())
2018-06-02 10:48:58.675151
datetime.timedelta(-1, 85429, 58707)
So it may not be possible in any way. I still think it would be useful for python to be able to do this kind of thing.
Upvotes: 0
Reputation: 70705
You cannot, for a pretty fundamental reason:
def f(arg=expression):
evaluates expression
at the time the def
statement is executed, and the object expression
evaluates to is saved in the function object as the default value of local name arg
. When the function body is executed, within the body arg
will simply retrieve the object expression
originally evaluated to. And nothing about any of that can be changed.
So, sure, you can supply a lambda
expression, but then arg
will be bound to the function object the lambda
expression returns. If you want to call that function object, you'll need to spell that as arg()
in the body. Plain old arg
will merely retrieve the function object.
Upvotes: 3
Reputation:
Can this be done with lambda ?
No. What you have is syntactically valid, but the default value of curr_time
ends up being the lambda function, not the datetime
value it would return if it were called. This can be worked around as:
if callable(curr_time):
curr_time = curr_time()
but at that point, you might as well just use the if curr_time is None:
approach you included in your question.
(Note that the comparison should be made as is None
, not == None
.)
Upvotes: 7