-
-
Notifications
You must be signed in to change notification settings - Fork 32k
Add __class_getitem__
to map
builtin, PEP 585
#108761
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
Comments
What about other builtin iterator classes, such as |
I don't know :) |
We had a similar discussion some time back for |
>>> type(map)
<class 'type'>
>>> type(callable)
<class 'builtin_function_or_method'> Plus, So, I don't think that this is the same problem. |
What does it mean and in what cases the type of the map iterator cannot be derived from types of |
@serhiy-storchaka I am sorry, I don't fully understand your question.
I don't think that this is related to CPython, because runtime does not derive anything at all. Typecheckers have different inference logic, so it is up to them to derive |
What does it mean for typecheckers and why they need it? |
But, we have to use string |
You didn't answer the question why you need it. |
An argument in favour is that this increases consistency with various other iterator classes that have >>> enumerate[str]
enumerate[str]
>>> import itertools
>>> itertools.chain[bytes]
itertools.chain[bytes] Additionally, adding the method would only cost two lines of C code, so the maintenance burden is not particularly high. However, I don't think the motivation here is very strong. You say:
However, I can't think of an instance where using Lines 6 to 9 in 578ebc5
Unless instances of an iterator class have some special attributes that set them apart from other iterator objects, I tend to think that people should avoid using any specific iterator class as a return annotation, and just use If we do want to add |
Since we have nominal type system, I general, I think that all type that are generic in typeshed should be generic in runtime. There's no real cost in doing so, but there's a big profit in making the DX pleasant for people who annotate their code. >>> from __future__ import annotations
>>> import beartype
>>> @beartype.beartype
... def returns_map() -> map[int]:
... ...
...
Traceback (most recent call last):
File "/Users/sobolev/Desktop/typeshed/.venv/lib/python3.11/site-packages/beartype/peps/_pep563.py", line 584, in resolve_pep563
func_hints_resolved[pith_name] = eval(
^^^^^
File "<string>", line 1, in <module>
TypeError: type 'map' is not subscriptable
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/sobolev/Desktop/typeshed/.venv/lib/python3.11/site-packages/beartype/_decor/_cache/cachedecor.py", line 77, in beartype
return beartype_object(obj, conf)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/sobolev/Desktop/typeshed/.venv/lib/python3.11/site-packages/beartype/_decor/decorcore.py", line 197, in beartype_object
return _beartype_func( # type: ignore[return-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/sobolev/Desktop/typeshed/.venv/lib/python3.11/site-packages/beartype/_decor/decorcore.py", line 608, in _beartype_func
bear_call.reinit(func, conf, **kwargs)
File "/Users/sobolev/Desktop/typeshed/.venv/lib/python3.11/site-packages/beartype/_check/checkcall.py", line 341, in reinit
resolve_pep563(
File "/Users/sobolev/Desktop/typeshed/.venv/lib/python3.11/site-packages/beartype/peps/_pep563.py", line 621, in resolve_pep563
raise BeartypePep563Exception(
beartype.roar.BeartypePep563Exception: function __main__.returns_map() return PEP 563-postponed type hint 'map[int]' syntactically invalid (i.e., "type 'map' is not subscriptable") under:
~~~~[ GLOBAL SCOPE ]~~~~
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'beartype': <module 'beartype' from '/Users/sobolev/Desktop/typeshed/.venv/lib/python3.11/site-packages/beartype/__init__.py'>, 'annotations': _Feature((3, 7, 0, 'beta', 1), None, 16777216)}
~~~~[ LOCAL SCOPE ]~~~~
{} But, if others don't agree for some reason: feel free to close, I don't care enough about this.
As I said, I think that this is a good thing, but I want to decouple these tasks. |
I'm a little wary of doing this for I'd be less wary if I thought there was an especially compelling use case, but I haven't any instances of people using map as a type, instead of Iterator (also struggled to find any on grep.app just now). In fact, I think I'm still slightly opposed to the decision to type them as classes in typeshed, see python/typeshed#5145. Also see faster-cpython/ideas#131. I think if we added Of course, this stops mattering in a PEP 718 world. |
You've given an example where a function that is annotated as returning Would beartype/Hypothesis/typeguard struggle with a from __future__ import annotations
from collections.abc import Iterator
def returns_map() -> Iterator[int]:
return map(len, [range(42)]) |
I think if PEP-718 is implemented the case for making |
I'd like to punt the decision here until PEP 718 is resolved. If it is accepted, we should also add subscript support to
If we make |
My 2 cents:
If PEP 718 is accepted, then all built-ins that are classes but are used like functions should be made subscriptable (namely all that were mentioned + Otherwise, if we want to stress that something was created using those builtins, I think the user should create something like that: from __future__ import annotations
from collections.abc import Iterator
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import TypeAlias
MapView: TypeAlias = Iterator
# or for versions supporting it:
# type MapView = Iterator and use it in stubs or |
Uh oh!
There was an error while loading. Please reload this page.
Feature or enhancement
Right now it is impossible to subscribe
map
:I propose adding
__class_getitem__
support tomap
, because it makes sense in some cases.However, https://peps.python.org/pep-0585/ does not say anything about
map
.First of all,
map
is defined asGeneric
intypeshed
:Full def: https://github.com/python/typeshed/blob/9552ec7f72f3190eb529aec096783c624b43bd29/stdlib/builtins.pyi#L1473-L1514
So, any person that wants to, say, return
map[str]
right now has to use'map[str]'
(via''
or viafrom __future__ import annotations
).Second, while we can treat
map[T]
as justIterator[T]
in parameter types, we always want to as specific as possible in return types.Third, it is a builtin, so we assume that it is widely used. And it actually is, even in CPython's source itself we can find usages that can be annotated as
map[whatever]
:cpython/Lib/zipfile/_path/__init__.py
Line 368 in 3047f09
cpython/Doc/library/itertools.rst
Line 808 in 3047f09
cpython/Doc/library/itertools.rst
Line 964 in 3047f09
cpython/Doc/library/itertools.rst
Line 1022 in 3047f09
cpython/Lib/importlib/resources/readers.py
Line 76 in 3047f09
cpython/Lib/logging/config.py
Line 112 in 3047f09
cpython/Lib/importlib/metadata/__init__.py
Line 540 in 3047f09
cpython/Lib/importlib/metadata/__init__.py
Line 787 in 3047f09
Lastly, it is a one-line change (+ tests) and many other builtins and stdlib objects support that already.
I cannot really think of any major cons.
Linked PRs
map
#108762The text was updated successfully, but these errors were encountered: