Mapping.get takes no keyword arguments, they are positional only. Why is this not detected by mypy if misused?
$ mypy --command "a: str = dict(b='yes').get('a', default='no')" Success: no issues found in 1 source file $ python Python 3.9.1 (default, Jan 13 2021, 15:21:08) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> a: str = dict(b='yes').get('a', default='no') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: dict.get() takes no keyword arguments
There’s a PR from 2016 where the convention is introduced that arguments starting with two underscores are positional only for mypy. Is this convention simply not followed in such a basic type? I’m wondering why.
Note that PEP 570 has been created 2018 has been just introduced with Python 3.8.
Many built-ins do not take keyword arguments, see this bug report, opened in 2010. The main reasons there are
- overhead: built-ins are implemented in C, and parsing either positional or keyword arguments comes with some computational overhead (although this seems to be alleviated in the meantime)
- little added value: typically, built-ins have reasonably small function signatures, so not having kwargs is not a big deal
- no demand: many built-ins are relatively old and around for a long time, w/o this being an issue in the past, which is historic evidence that there is no demand from devs to have kwargs
- a lot of effort: positional arguments can be renamed easily, their scope is limited to the implementation of the function itself, not on the callers; kwargs kind of become part of the language and need to be well thought out as they cannot be easily changed later
Thus, mypy should report the error, but it doesn’t. As built-ins stubs are typed in typeshed, there is an open bug report in the typeshed issue tracker at github.