Is It Pythonic: Naming Lambdas

Is it pythonic: naming lambdas

This is not Pythonic and PEP8 discourages it:

Always use a def statement instead of an assignment statement that
binds a lambda expression directly to an identifier.

Yes:

def f(x): return 2*x

No:

f = lambda x: 2*x

The first form means that the name of the resulting function object is
specifically 'f' instead of the generic '<lambda>'. This is more
useful for tracebacks and string representations in general. The use
of the assignment statement eliminates the sole benefit a lambda
expression can offer over an explicit def statement (i.e. that it can
be embedded inside a larger expression)

A rule of thumb for this is to think on its definition: lambdas expressions are anonymous functions. If you name it, it isn't anonymous anymore. :)

Get lambda function's name as string

Lambdas are anonymous, which means they do not have a name.

You can always assign a name to __name__ if you feel they should have one anyway:

myfunc_l = lambda: None
myfunc_l.__name__ = 'foo'

Note that Python cannot know that you assigned the lambda function object to a specific name; the assignment takes place after the lambda expression was executed. Remember, you don't even have to assign a lambda:

result = (lambda x: x ** 2)(4)

or you could store the lambda in a list:

several_lambdas = [lambda y: (y // 2) for y in range(10, 20)]

and in neither context is there a name to assign to these objects.

Full-blown function definitions on the other hand are statements, not expressions, and the def statement requires that you specify a name. You can never use a def statement without naming the resulting function, which is why Python can assign the name to the object:

>>> def foo(): pass
...
>>> print foo.__name__
'foo'

You can still assign foo to something else, delete the foo global reference, rename the function object by assigning to the __name__ attribute, but it won't change the nature of the function. lambdas are the same, really, apart from the fact that there's no context to set the initial name (and the fact that they can only represent a single expression).

Which is more preferable to use: lambda functions or nested functions ('def')?

If you need to assign the lambda to a name, use a def instead. defs are just syntactic sugar for an assignment, so the result is the same, and they are a lot more flexible and readable.

lambdas can be used for use once, throw away functions which won't have a name.

However, this use case is very rare. You rarely need to pass around unnamed function objects.

The builtins map() and filter() need function objects, but list comprehensions and generator expressions are generally more readable than those functions and can cover all use cases, without the need of lambdas.

For the cases you really need a small function object, you should use the operator module functions, like operator.add instead of lambda x, y: x + y

If you still need some lambda not covered, you might consider writing a def, just to be more readable. If the function is more complex than the ones at operator module, a def is probably better.

So, real world good lambda use cases are very rare.

When I change the variable name in a lambda function, the result changes

You're not saving the variable's value inside the lambda. You're saving a variable defined outside of the lambda. It's not necessarily a global variable, but to the scope of the lambda, it is declared outside of it. When the iteration terminates, the value of i is 2. That's why when you iterate with for-loop using j, the value inside the lambda is always 2.

When you iterate on a for-loop using the i variable, you're once again changing the state of i before executing the lambda. That's why it gives you a different result.

To make the lambda get the variable's value only without keeping it dependant of any variable scope, do something like this:

a = []
for i in range(3):
a.append((lambda k: lambda x:(k+x))(i))

lambda k: ... is used to pass the state of i to the inner lambda. It's in fact executing the function, and returning lambda x: (k+x), where k is a private variable from the lambda's scope.

Now when you try to print it using another variable, such as j, or assigning a new value to i or k:

i = 256
k = 512

for j in range(3):
print(a[j](0))

The output is:

0
1
2

Python: Difference between passing lambda function and class name as arguments

Is there any advantage in using a the lambda keyword over just passing the class name?

Not really. In the simple case you show, you are just adding a (IMHO unneeded) level of indirection to the instantiation process. Using the class name itself would be simpler and more comprehensible.

The only advantage that comes to my mind, is that lambda functions offer the possibility to pass further arguments along:

Yeah, that's a good use case. In fact, it's such a common use case that functools.partial() was invented exactly for this purpose:

from functools import partial

clazz_fn3 = partial(Clazz, b=42)
c3 = clazz_fn3(3)
print(c3)

So are there further differences between the two options or is this a purely stylistic choice?

I'd say this is most definitely a stylistic choice of the programmer. Other than the obvious difference in the slightly more (unneeded) overhead when wrapping using a lambda, there isn't much else of objective relevance that'd make one of the two versions preferable over the other.

How are lambdas useful?

Are you talking about lambda expressions? Like

lambda x: x**2 + 2*x - 5

Those things are actually quite useful. Python supports a style of programming called functional programming where you can pass functions to other functions to do stuff. Example:

mult3 = filter(lambda x: x % 3 == 0, [1, 2, 3, 4, 5, 6, 7, 8, 9])

sets mult3 to [3, 6, 9], those elements of the original list that are multiples of 3. This is shorter (and, one could argue, clearer) than

def filterfunc(x):
return x % 3 == 0
mult3 = filter(filterfunc, [1, 2, 3, 4, 5, 6, 7, 8, 9])

Of course, in this particular case, you could do the same thing as a list comprehension:

mult3 = [x for x in [1, 2, 3, 4, 5, 6, 7, 8, 9] if x % 3 == 0]

(or even as range(3,10,3)), but there are many other, more sophisticated use cases where you can't use a list comprehension and a lambda function may be the shortest way to write something out.

  • Returning a function from another function

      >>> def transform(n):
    ... return lambda x: x + n
    ...
    >>> f = transform(3)
    >>> f(4)
    7

    This is often used to create function wrappers, such as Python's decorators.

  • Combining elements of an iterable sequence with reduce()

      >>> reduce(lambda a, b: '{}, {}'.format(a, b), [1, 2, 3, 4, 5, 6, 7, 8, 9])
    '1, 2, 3, 4, 5, 6, 7, 8, 9'
  • Sorting by an alternate key

      >>> sorted([1, 2, 3, 4, 5, 6, 7, 8, 9], key=lambda x: abs(5-x))
    [5, 4, 6, 3, 7, 2, 8, 1, 9]

I use lambda functions on a regular basis. It took me a while to get used to them, but eventually I came to understand that they're a very valuable part of the language.

programmatically setting names of lambda function

replace:

myfun = lambda x:2*x

with:

def myfun(x):
"""doubles the input parameter"""
return 2 * x

How to find out if a function has been declared by `lambda` or `def`?

AFAIK, you cannot reliably in Python 3.

Python 2 used to define a bunch of function types. For that reason, methods, lambdas and plain functions have each their own type.

Python 3 has only one type which is function. There are indeed different side effects where declaring a regular function with def and a lambda: def sets the name to the name (and qualified name) of the function and can set a docstring, while lambda sets the name (and qualified name) to be <lambda>, and sets the docstring to None. But as this can be changed...

If the functions are loaded from a regular Python source (and not typed in an interactive environment), the inspect module allows to access the original Python code:

import inspect

def f(x):
return x**2

g = lambda x: x**2

def is_lambda_func(f):
"""Tests whether f was declared as a lambda.

Returns: True for a lambda, False for a function or method declared with def
Raises:
TypeError if f in not a function
OSError('could not get source code') if f was not declared in a Python module
but (for example) in an interactive session
"""
if not inspect.isfunction(f):
raise TypeError('not a function')
src = inspect.getsource(f)
return not src.startswith('def') and not src.startswith('@') # provision for decorated funcs

g.__name__ = 'g'
g.__qualname__ = 'g'

print(f, is_lambda_func(f))
print(g, is_lambda_func(g))

This will print:

<function f at 0x00000253957B7840> False
<function g at 0x00000253957B78C8> True

By the way, if the problem was serialization of function, a function declared as a lambda can successfully be pickled, provided you give it a unique qualified name:

>>> g = lambda x: 3*x
>>> g.__qualname__ = "g"
>>> pickle.dumps(g)
b'\x80\x03c__main__\ng\nq\x00.'


Related Topics



Leave a reply



Submit