Peter Moore
Peter Moore

Reputation: 2096

can a lambda or other method be used as a default parameter in python

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

Answers (3)

Peter Moore
Peter Moore

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

Tim Peters
Tim Peters

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

user149341
user149341

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

Related Questions