43

consider:

blank_fn = lambda *args, **kwargs: None

def callback(x, y, z=''):
    print x, y, z

def perform_task(callback=blank_fn):
    print 'doing stuff'
    callback('x', 'y', z='z' )

The motivation for doing it this way is I don't have to put in logic to check if callback has been assigned because it defaults to blank_fn which just does nothing.

This works, but is there some reason I shouldn't do it? Is it pythonic? Is there a better way to do it? Is there a built-in for:

lambda *args, **kwargs: None
Scruffy
  • 908
  • 1
  • 8
  • 21
  • 8
    Using `lambda` to define a named function is not Pythonic, no. Use `def`. – Wooble Aug 02 '13 at 19:17
  • @Wooble lambda is not complex, or even complicated. Therefore I would say it is Pythonic. Plus it's super handy! – Gavin Ray Feb 26 '22 at 06:30
  • 2
    It seems that `f = lambda *args, **kwargs: 1234` works in Python 3.8. You can call it with `f()`, `f(1, 2, 3)` or even `f(1, 2, foo=bar)` and it always returns 1234. – Basj Jun 15 '22 at 08:26

2 Answers2

51

According to PEP8, you should "Always use a def statement instead of an assignment statement that binds a lambda expression directly to a name." So, one thing I would change is:

def blank_fn(*args, **kwargs):
    pass

However, I think a more pythonic way to do this is:

def perform_task(callback=None):
    print 'doing stuff'
    if callback is not None:
        callback('x', 'y', z='z')

There shouldn't be any need to call a function that does nothing. Truth value testing is cheaper than function calling.

def do_nothing(*args, **kwargs): pass
def do_something(arg, callback=do_nothing):
    a = 1 + 2
    callback('z', z='z')
def do_something_else(arg, callback=None):
    a = 1 + 2
    if callback is not None:
        callback('z', z='z')

%timeit do_something(3)
1000000 loops, best of 3: 644 ns per loop

%timeit do_something_else(3)
1000000 loops, best of 3: 292 ns per loop
Chris Barker
  • 2,279
  • 14
  • 15
  • 2
    Ok. I suppose if I did have a legit default callback I could def it and pass it as default. Otherwise I'll use the boring old if... None:. Blech! – Scruffy Aug 02 '13 at 19:23
  • 6
    Sometimes it happens that perform_task does some complicated job and you want to factor as much as possible out of it. Many small steps like taking the blank_fn way can lead to a nice, manageable code. And often it is more important to keep the code clean rather than optimize it. – Dawid Toton Sep 04 '17 at 14:43
0

I think the previous answer is superior, as it provides a better way to accomplish what the OP wanted to do.

However there may arguably be circumstances when you want a noop function when testing, or if you are monkey patching something.

So to answer the OP Question as asked, you can use Mock:

In [1]: from mock import Mock

In [2]: blank_fn = Mock(return_value=None)

In [3]: blank_fn()

In [4]: blank_fn("foo")

In [5]: blank_fn(bar="foo")

In [6]: blank_fn("foobar", bar="foo")

In [7]: 
DRendar
  • 1,798
  • 1
  • 13
  • 5
  • 4
    It seems like extremely poor practice to use mock anywhere outside of a test suite. What advantage does this have over just declaring an empty function? This is probably much slower too – Cruncher Jul 09 '19 at 19:20