Skip to content

Commit 3244b64

Browse files
Write the post
1 parent 6d026c9 commit 3244b64

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

docs/guides/lambda.rst

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,65 @@
1+
*****************************************
2+
The Trouble (Or Lack Thereof) With Lambda
3+
*****************************************
14

5+
:ref:`Lambda` expressions are a common and useful part of the Python programming language.
6+
However, there is one problem with them: syntactically, they do not allow for type
7+
annotations. While it is perfectly simple to write ``lambda x: x``, you cannot directly
8+
indicate a type for x. (Type annotations are indicated by a colon, and so is the end
9+
of the lambda parameter list. Where would the type annotation go?)
10+
11+
However, despite this infelicity, lambda expressions are not immune from static typing,
12+
and in fact follow the same static type rules as everything else. Type checkers try
13+
to deduce the type of the lambda arguments and return value, and if they can't they
14+
fall back to ``Any``. Due to the inability to directly indicate types for these,
15+
``Any`` tends to pop up quite often here. This means that many type errors may occur
16+
here unnoticed, which is bad. For instance, the following example is a runtime type
17+
error, but is uncaught in most (perhaps all) type checkers:
18+
19+
.. code-block:: python
20+
21+
f1 = lambda a, b: a * b
22+
f1(1, "a")
23+
24+
(The alternative way of writing this, ``(lambda a, b: a + b)(1, "a")``, is typically
25+
caught by type checkers, because it is simple and immediate enough that they are able
26+
to deduce that a type error will occur.)
27+
28+
There are some workarounds to this problem, which all involve assigning the lambda to
29+
something, in one way or another, and annotating that. This is a bit unfortunate,
30+
because the idiomatic use of a lambda involves not doing that. In fact, at that point
31+
you might as well just define a normal function. Let's call that our first workaround.
32+
33+
``def f(x: object) -> object: return x``
34+
35+
The second workaround is equivalent: assigning the lambda to a variable, and annotating
36+
the type of that variable with a :ref:`Callable`
37+
38+
``f: Callable[[object], object] lambda x: x``
39+
40+
:ref:`Type comments on function definitions` do not actually work on lambda, nor do
41+
normal :ref:`Type comments` help (although you can use a type commment on an assignment
42+
to a variable with a lambda, of course; however this will have to be the Callable
43+
syntax and not the function-arrow special one).
44+
45+
Most type checkers include an option to emit a warning if they aren't able to deduce
46+
the type of an expression; this should be helpful if you want to avoid silent uncaught
47+
type errors resulting from lambda expressions being deduced as ``Any``.
48+
49+
In conclusion:
50+
51+
1. There is no way to explicitly annotation lambda arguments or return values in the
52+
lmabdas themselves.
53+
54+
2. However, static typing rules still apply to lambdas, including type deduction.
55+
56+
3. Many lambdas get deduced as ``Any``, which might suppress the reporting of other
57+
type errors.
58+
59+
4. However, many lambdas get deduced fine, and for those it's not a problem.
60+
61+
5. If you want to annotate the type of lambdas, you can bind them and annotate them
62+
there.
63+
64+
6. Most type checkers have a setting that will warn you if anything gets deduced as
65+
``Any``, and you can use that to avoid false negatives relating to lambda.

0 commit comments

Comments
 (0)