PEP 3332: Extending lambda expressions

Let's get onto it already: if you aren't familiar with expressions made with lambda keyword, there is following syntax:

lambda [p1[, p2[, p3[, ]]]]: <return-code-scrap>

where [p1[, p2[, p3[, ... ]]]] are parameters. Because they are encased with squared parentheses, they are optional. <return-code-scrap> can be anything, the return keyword shouldn't be used to precede the value from either variable or function, which should be returned. If lambda expression was assigned to a variable, that variable becomes callable.

c1lambda: 3 once called, returns 3. Lack of parameters
c2lambda x: x once called, returns anything passed to the parameter
c3_1lambda x1, x2: (x1, x2) once called, returns anything passed to the parameters, in a 2-item tuple
c3_2lambda x1, x2: x1, x2 shortened tuple notation doesn't work on lambda expressions, x2 is undefined after comma
c3_3lambda x1, x2: x1, lambda expression is placed in a tuple, call as c3_3[0](x1, x2)

These examples are quite simple, however, the one with c3_2 variable would bind with some explanations: if we allowed shortened tuple notation, as in return x1, x2, this would bind with different error, if that expression was appended to a parameter (no matter, if positional-only or keyword-only). There rather come up with version with variable c3_1. Lambda expressions in C++, comparing to these in Python, are extensible, because their bodies are defined via curly brackets {}.

auto c1[]() { return 3; };

This one is equivalent to previous example with c1 variable. The C language does not support lambda expressions, while C++ has them since C++11. In Python, you don't use curly parentheses, but mere circled brackets () and indentations. But let's go back to lambda expressions in Python. In my opinion, they need improvement. I did read a book, which author is Julien Danjou, titled Serious Python. Black-Belt Advice on Deployment, Scalability, Testing and More (2019), and author of this book presented its better alternative - functools.partial class, in page 143. Python 3 working team had also aspirations to remove the lambda keyword, along with its expressions, but because programmers had no different way to implement it, it has been finally kept, as-is (Danjou in his book only said that in Python 3 lambda keyword was qualified to be removed).

Lambda expressions can only contain one line of the code, so this is not like syntax for factual functions. In most cases we can create a function, and pass it to a variable or parameter without circled parentheses.

def c1_tmp():
   return 3

c1c1_tmp once called, returns 3. Lack of parameters

Next difference concerning lambda expressions in Python and C++ is that the second language allows (and even requires) to provide parameter types. But unlike in Python, types in both C and C++ cannot be united unless... the std::variant generic class. In Python, you cannot type hint any of provided parameters in a lambda expression, what forces programmers to create a function, and pass it to a variable or parameter, without circled brackets. To re-create example with c2 variable, all we would need is generic type.

auto c2[]<typename T>(T v) { return v; };

To do the same in Python, we will need to create a function again, just as:

from typing import TypeVar

TTypeVar(T)

def c2_tmp(v: T):
   return v

c2c2_tmp once called, returns anything passed to the parameter

So what do I want? As I said, extending possibilities of lambda expressions in Python, so that it becomes more satisfying to create callback variable (referring to JavaScript). Parameters list, just like in normal functions, but also in lambda expressions in C++, should be encased with circled brackets. Doing this allow to extend the code with leading lambda keyword. Code will become elastic. Circled parentheses would also allow type hinting for parameters, without being scared of colon after which begins return code part of lambda expression. Below new version of lambda expressions syntax:

syntax for Python versions least than 3.12
from typing import TypeVar

T1TypeVar(T1)
T2TypeVar(T2)
T3TypeVar(T3)
...

lambda ([p1[: T1][, p2[: T2][, p3[: T3][, [: ]]]]]): <return-code-scrap>

syntax for Python versions equal or greater than 3.12
lambda [T1, T2, T3, ]([p1[: T1][, p2[: T2][, p3[: T3][, [: ]]]]]): <return-code-scrap>

This syntax doesn't have to overwrite the current syntax, as we saw from the beginning of this article. Moreover, I think syntax shouldn't be deputized with the one I just coined, because seeing this code in Python 2 (for example) would lead to syntax error, and libraries written with old lambda expression syntax would need to migrate to Python 3 utterly and base on this syntax. So keeping the old lambda expression syntax is completely mandatory. If instead of <return-code-scrap> we put regular lambda body, its code will become less understanding and will decrease readability, it also will become less logical, especially when passing lambda expression to a parameter, and again would push programmers to define their own functions with def keyword. I know that lambda expressions can be replaced with instances of class functools.partial, but since lambda expressions remain in Python 3, we could care for its development.

Article written by Aveyzan on 26th August 2024, 0:21 AM according to time in Greenwich