From acc78f13a217b2dd7620f08838ac0fb6385871b2 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Mon, 20 Oct 2025 04:34:33 -0400 Subject: [PATCH 1/7] Add 'lambda' --- docs/guides/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/guides/index.rst b/docs/guides/index.rst index b13e0348..70dfdac9 100644 --- a/docs/guides/index.rst +++ b/docs/guides/index.rst @@ -12,6 +12,7 @@ Type System Guides :caption: Contents: libraries + lambda writing_stubs modernizing unreachable From a61ff6b6388600095cc28c248787de34106d7e6f Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Mon, 20 Oct 2025 04:37:29 -0400 Subject: [PATCH 2/7] Add lambda guide to documentation index --- docs/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.rst b/docs/index.rst index 19117d05..0fcbf9a7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -23,6 +23,7 @@ Guides :maxdepth: 1 guides/libraries + guides/lambda guides/writing_stubs guides/modernizing guides/unreachable From 6d026c9ebd4fe9981125169110daeee8fdd2384e Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Mon, 20 Oct 2025 04:38:01 -0400 Subject: [PATCH 3/7] Create lambda.rst --- docs/guides/lambda.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/guides/lambda.rst diff --git a/docs/guides/lambda.rst b/docs/guides/lambda.rst new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/docs/guides/lambda.rst @@ -0,0 +1 @@ + From 3244b64dddf93b8ca8d20dbfbb7a5ee2816d73e9 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Mon, 20 Oct 2025 05:20:04 -0400 Subject: [PATCH 4/7] Write the post --- docs/guides/lambda.rst | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/docs/guides/lambda.rst b/docs/guides/lambda.rst index 8b137891..0b8b5c16 100644 --- a/docs/guides/lambda.rst +++ b/docs/guides/lambda.rst @@ -1 +1,65 @@ +***************************************** +The Trouble (Or Lack Thereof) With Lambda +***************************************** +:ref:`Lambda` expressions are a common and useful part of the Python programming language. +However, there is one problem with them: syntactically, they do not allow for type +annotations. While it is perfectly simple to write ``lambda x: x``, you cannot directly +indicate a type for x. (Type annotations are indicated by a colon, and so is the end +of the lambda parameter list. Where would the type annotation go?) + +However, despite this infelicity, lambda expressions are not immune from static typing, +and in fact follow the same static type rules as everything else. Type checkers try +to deduce the type of the lambda arguments and return value, and if they can't they +fall back to ``Any``. Due to the inability to directly indicate types for these, +``Any`` tends to pop up quite often here. This means that many type errors may occur +here unnoticed, which is bad. For instance, the following example is a runtime type +error, but is uncaught in most (perhaps all) type checkers: + +.. code-block:: python + + f1 = lambda a, b: a * b + f1(1, "a") + +(The alternative way of writing this, ``(lambda a, b: a + b)(1, "a")``, is typically +caught by type checkers, because it is simple and immediate enough that they are able +to deduce that a type error will occur.) + +There are some workarounds to this problem, which all involve assigning the lambda to +something, in one way or another, and annotating that. This is a bit unfortunate, +because the idiomatic use of a lambda involves not doing that. In fact, at that point +you might as well just define a normal function. Let's call that our first workaround. + +``def f(x: object) -> object: return x`` + +The second workaround is equivalent: assigning the lambda to a variable, and annotating +the type of that variable with a :ref:`Callable` + +``f: Callable[[object], object] lambda x: x`` + +:ref:`Type comments on function definitions` do not actually work on lambda, nor do +normal :ref:`Type comments` help (although you can use a type commment on an assignment +to a variable with a lambda, of course; however this will have to be the Callable +syntax and not the function-arrow special one). + +Most type checkers include an option to emit a warning if they aren't able to deduce +the type of an expression; this should be helpful if you want to avoid silent uncaught +type errors resulting from lambda expressions being deduced as ``Any``. + +In conclusion: + +1. There is no way to explicitly annotation lambda arguments or return values in the +lmabdas themselves. + +2. However, static typing rules still apply to lambdas, including type deduction. + +3. Many lambdas get deduced as ``Any``, which might suppress the reporting of other +type errors. + +4. However, many lambdas get deduced fine, and for those it's not a problem. + +5. If you want to annotate the type of lambdas, you can bind them and annotate them +there. + +6. Most type checkers have a setting that will warn you if anything gets deduced as +``Any``, and you can use that to avoid false negatives relating to lambda. From f808b7af84bd3242a48b887aa828d09ac751c441 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Mon, 20 Oct 2025 05:29:10 -0400 Subject: [PATCH 5/7] Update lambda.rst: remove the refs since I don't want to hunt them down nor verify them --- docs/guides/lambda.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/guides/lambda.rst b/docs/guides/lambda.rst index 0b8b5c16..bb0f9ba8 100644 --- a/docs/guides/lambda.rst +++ b/docs/guides/lambda.rst @@ -2,7 +2,7 @@ The Trouble (Or Lack Thereof) With Lambda ***************************************** -:ref:`Lambda` expressions are a common and useful part of the Python programming language. +Lambda expressions are a common and useful part of the Python programming language. However, there is one problem with them: syntactically, they do not allow for type annotations. While it is perfectly simple to write ``lambda x: x``, you cannot directly indicate a type for x. (Type annotations are indicated by a colon, and so is the end @@ -33,12 +33,12 @@ you might as well just define a normal function. Let's call that our first worka ``def f(x: object) -> object: return x`` The second workaround is equivalent: assigning the lambda to a variable, and annotating -the type of that variable with a :ref:`Callable` +the type of that variable with a Callable. ``f: Callable[[object], object] lambda x: x`` -:ref:`Type comments on function definitions` do not actually work on lambda, nor do -normal :ref:`Type comments` help (although you can use a type commment on an assignment +Type comments on function definitions do not actually work on lambda, nor do +normal type comments help (although you can use a type commment on an assignment to a variable with a lambda, of course; however this will have to be the Callable syntax and not the function-arrow special one). From 3e237d3e8153f8b4824b364d17c62ab3b5155196 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Mon, 20 Oct 2025 05:31:57 -0400 Subject: [PATCH 6/7] Update lambda.rst: typos --- docs/guides/lambda.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/guides/lambda.rst b/docs/guides/lambda.rst index bb0f9ba8..8d0ce719 100644 --- a/docs/guides/lambda.rst +++ b/docs/guides/lambda.rst @@ -35,10 +35,10 @@ you might as well just define a normal function. Let's call that our first worka The second workaround is equivalent: assigning the lambda to a variable, and annotating the type of that variable with a Callable. -``f: Callable[[object], object] lambda x: x`` +``f: Callable[[object], object] = lambda x: x`` Type comments on function definitions do not actually work on lambda, nor do -normal type comments help (although you can use a type commment on an assignment +normal type comments help (although you can use a type comment on an assignment to a variable with a lambda, of course; however this will have to be the Callable syntax and not the function-arrow special one). @@ -48,8 +48,8 @@ type errors resulting from lambda expressions being deduced as ``Any``. In conclusion: -1. There is no way to explicitly annotation lambda arguments or return values in the -lmabdas themselves. +1. There is no way to explicitly annotate lambda arguments or return values in the +lambdas themselves. 2. However, static typing rules still apply to lambdas, including type deduction. From f9fa5910ca87374891bdcd85f2d2916907bfa1a7 Mon Sep 17 00:00:00 2001 From: wyattscarpenter Date: Sat, 25 Oct 2025 14:26:44 -0400 Subject: [PATCH 7/7] Update lambda.rst: Typos, Jelle suggestions, and comment elaborations. --- docs/guides/lambda.rst | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/docs/guides/lambda.rst b/docs/guides/lambda.rst index 8d0ce719..65c6074a 100644 --- a/docs/guides/lambda.rst +++ b/docs/guides/lambda.rst @@ -18,13 +18,27 @@ error, but is uncaught in most (perhaps all) type checkers: .. code-block:: python - f1 = lambda a, b: a * b + f1 = lambda a, b: a + b f1(1, "a") (The alternative way of writing this, ``(lambda a, b: a + b)(1, "a")``, is typically caught by type checkers, because it is simple and immediate enough that they are able to deduce that a type error will occur.) +.. + (This is an RST comment.) + A slightly more realistic example of an uncaught lambda type error is + + .. code-block :: python + def apply(f, *x): + f(*x) + apply((lambda a, b: a + b), 1, "a") + + since it doesn't immediately defeat the purpose of a lambda by binding it. + It also fails to get caught by mypy and pyright in their default modes, as + required for the example. However, it's a little bit harder to understand, + so we went with the other one. + There are some workarounds to this problem, which all involve assigning the lambda to something, in one way or another, and annotating that. This is a bit unfortunate, because the idiomatic use of a lambda involves not doing that. In fact, at that point @@ -37,14 +51,23 @@ the type of that variable with a Callable. ``f: Callable[[object], object] = lambda x: x`` -Type comments on function definitions do not actually work on lambda, nor do -normal type comments help (although you can use a type comment on an assignment -to a variable with a lambda, of course; however this will have to be the Callable -syntax and not the function-arrow special one). +.. + (This is an RST comment. The following paragraph has been excised from the guide, + as most beginners will not know what a type comment is anyway — especially a function + type comment. However, the paragraph is left in this comment for greater context for + you, the future editor:) + + Type comments on function definitions do not actually work on lambda, nor do + normal type comments help (although you can use a type comment on an assignment + to a variable with a lambda, of course; however this will have to be the Callable + syntax and not the function-arrow special one). Most type checkers include an option to emit a warning if they aren't able to deduce the type of an expression; this should be helpful if you want to avoid silent uncaught -type errors resulting from lambda expressions being deduced as ``Any``. +type errors resulting from lambda expressions being deduced as ``Any``. For instance, +Mypy includes ``disallow_any_expr``/``--disallow-any-expr`` and Pyright includes +``reportUnknownLambdaType``. Both of those options are set to true in the respective +strict modes of those type checkers. In conclusion: