-
Notifications
You must be signed in to change notification settings - Fork 275
Document the trouble with lambdas in the guides #2105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
wyattscarpenter
wants to merge
7
commits into
python:main
Choose a base branch
from
wyattscarpenter:patch-1
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+90
−0
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
acc78f1
Add 'lambda'
wyattscarpenter a61ff6b
Add lambda guide to documentation index
wyattscarpenter 6d026c9
Create lambda.rst
wyattscarpenter 3244b64
Write the post
wyattscarpenter f808b7a
Update lambda.rst: remove the refs since I don't want to hunt them do…
wyattscarpenter 3e237d3
Update lambda.rst: typos
wyattscarpenter f9fa591
Update lambda.rst: Typos, Jelle suggestions, and comment elaborations.
wyattscarpenter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ Type System Guides | |
| :caption: Contents: | ||
|
|
||
| libraries | ||
| lambda | ||
| writing_stubs | ||
| modernizing | ||
| unreachable | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| ***************************************** | ||
| The Trouble (Or Lack Thereof) With Lambda | ||
| ***************************************** | ||
|
|
||
| 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.) | ||
|
|
||
| .. | ||
| (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 | ||
| 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 Callable. | ||
|
|
||
| ``f: Callable[[object], object] = lambda x: x`` | ||
|
|
||
| .. | ||
| (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``. 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: | ||
|
|
||
| 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. | ||
|
|
||
| 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. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.