Without `pass` and `...`, are there better ways to intend “Do nothing“ with a lambda?

Some uses pass statement to intend “Do nothing“ and some uses Ellipsis(…) to intend “Later impliment code“ according to the article and the article.

But pass cannot be used with a lambda to intend “Do nothing“ while Ellipsis(…) can but it intends “Later impliment code“ and I can still use a string to intend “Do nothing“ but it’s long as show below:

v1 = lambda: pass          # Error
v2 = lambda: ...           # No error
v3 = lambda: "Do nothing"  # No error

So, are there better ways to intend “Do nothing“ with a lambda?

v1 = lambda: None

4 Likes

lambda: ... does not “do nothing”. It returns the literal ellipsis as a value:

>>> print((lambda: ...)())
Ellipsis

Remember that f = lambda *args, **kwargs: expression is syntactic sugar for

def f(*args, **kwargs):
    return expression

so your examples become

def v1():
    return pass

def v2():
    return ...

def v3():
    return "Do nothing"

It’s easy to see why v1 is then an error, because return pass is a syntax error.

To reverse the function syntax into a lambda, remember that def f(): pass is the same as def f(): return None. Therefore, you can turn a do-nothing function into a lambda as lambda: None.

9 Likes

pass is a do-nothing statement that doesn’t do anything special as the only statement in a function; you still execute it and reach the end of the body without an explicit return, so None is returned implicitly. The equivalent lambda expression would be lambda: None. There’s no implicit return value for a lambda expression; you have to supply None explicitly.

However, you shouldn’t be writing f = lambda: None in the first place, whether or not this is a placeholder. If the function needs a name, use def. Lambda expressions are for places where a function will be implicitly bound (such as an argument for a function call) or for functions whose reference is stored implicitly in a container. If you need a placeholder, use

def f():
    ...

result = foo(f) 

until f has a body that you know can be expressed as a single expression, at which point you inline the definition if that makes sense.

result = foo(lambda: do_something() + do_something_else())

The lambda body needs ot be an expression that evaluates to a certain value. pass is a statement but not an expression. Function calls are expressions as they always return something (including None) or raise an exception.

In case of a not-yet-implemented lambda, we probably don’t want it to be invoked, so we can raise an exception (NotImplementedError will be the most appropriate):

>>> def NotYetImplemented(msg=""):
...     raise NotImplementedError(msg)
... 
>>> v1 = lambda *_: NotYetImplemented()
>>> v1()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    v1()
    ~~^^
  File "<stdin>", line 1, in <lambda>
    v1 = lambda *_: NotYetImplemented()
                    ~~~~~~~~~~~~~~~~~^^
  File "<stdin>", line 2, in NotYetImplemented
    raise NotImplementedError(msg)
NotImplementedError

Note that raise is not an expression and cannot be used directly in the lambda, therefore I have to wrap it in a function NotYetImplemented which actually constructs and raises the exception.

For decorator, the best is lambda _: _.
For runtime calling, it is lambda: None