type testing #15

Closed
opened 2021-06-08 14:19:35 +08:00 by sb10q · 8 comments

Python seems to want isinstance(obj, the_type) and not type(obj) === the_type.

Python seems to want ``isinstance(obj, the_type)`` and not ``type(obj) === the_type``.
Poster
Owner
>>> x = [1, 2, 3]
>>> from typing import List
>>> type(x) == List
False
>>> type(x) == list
True
>>> isinstance(x, list)
True
>>> isinstance(x, List)
True
>>> isinstance(x, List[int])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/nix/store/4s0h5aawbap3xhldxhcijvl26751qrjr-python3-3.8.9/lib/python3.8/typing.py", line 769, in __instancecheck__
    return self.__subclasscheck__(type(obj))
  File "/nix/store/4s0h5aawbap3xhldxhcijvl26751qrjr-python3-3.8.9/lib/python3.8/typing.py", line 777, in __subclasscheck__
    raise TypeError("Subscripted generics cannot be used with"
TypeError: Subscripted generics cannot be used with class and instance checks
```text >>> x = [1, 2, 3] >>> from typing import List >>> type(x) == List False >>> type(x) == list True >>> isinstance(x, list) True >>> isinstance(x, List) True >>> isinstance(x, List[int]) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/nix/store/4s0h5aawbap3xhldxhcijvl26751qrjr-python3-3.8.9/lib/python3.8/typing.py", line 769, in __instancecheck__ return self.__subclasscheck__(type(obj)) File "/nix/store/4s0h5aawbap3xhldxhcijvl26751qrjr-python3-3.8.9/lib/python3.8/typing.py", line 777, in __subclasscheck__ raise TypeError("Subscripted generics cannot be used with" TypeError: Subscripted generics cannot be used with class and instance checks ```
Poster
Owner

But, we might still want our own function that can be used with "subscripted generics".

But, we might still want our own function that can be used with "subscripted generics".

But, we might still want our own function that can be used with "subscripted generics".

I don't think subscripted generics can be tested in Python. In general, we can just discard the generic paramter, and there would be no way to get it back, so there is no way to test it. For containers that uses generic parameters such as lists, it is possible to have elements of different types, so the function has to scan through the whole object possibly recursively, which is not efficient.

Python seems to want isinstance(obj, the_type) and not type(obj) === the_type.

Forgot this previously. We can use this, the syntax is not a big issue. Will open another PR.

> But, we might still want our own function that can be used with "subscripted generics". I don't think subscripted generics can be tested in Python. In general, we can just discard the generic paramter, and there would be no way to get it back, so there is no way to test it. For containers that uses generic parameters such as lists, it is possible to have elements of different types, so the function has to scan through the whole object possibly recursively, which is not efficient. > Python seems to want ``isinstance(obj, the_type)`` and not ``type(obj) === the_type``. Forgot this previously. We can use this, the syntax is not a big issue. Will open another PR.
Poster
Owner

For containers that uses generic parameters such as lists, it is possible to have elements of different types, so the function has to scan through the whole object possibly recursively, which is not efficient.

The goal here is to have the same behavior in the interpreter and NAC3.

In NAC3 I think we want to be able to test for List[float] vs. List[int] for example.

In the interpreter we can:

  • as you suggest scan through the whole list and look at the type of each element, which is inefficient indeed, or
  • assume that the user passed a well-formed list and simply test the first element for float vs. int.

The simulator could have a debug/performance switch that selects either behavior.

> For containers that uses generic parameters such as lists, it is possible to have elements of different types, so the function has to scan through the whole object possibly recursively, which is not efficient. The goal here is to have the same behavior in the interpreter and NAC3. In NAC3 I think we want to be able to test for ``List[float]`` vs. ``List[int]`` for example. In the interpreter we can: * as you suggest scan through the whole list and look at the type of each element, which is inefficient indeed, or * assume that the user passed a well-formed list and simply test the first element for float vs. int. The simulator could have a debug/performance switch that selects either behavior.

For option two, perhaps we should do something like this:

>>> from typing import List, Tuple, get_origin, get_args
>>> def is_type(x, T):
...     outer = get_origin(T)
...     if outer is None:
...         outer = T
...     if not isinstance(x, outer):
...         return False
...     if isinstance(x, List):
...         return len(x) == 0 or is_type(x[0], get_args(T)[0])
...     if isinstance(x, tuple):
...         return len(x) == len(get_args(T)) and 
...                all([is_type(i, j) for i, j in zip(x, get_args(T))])
...     return True
... 
>>> is_type([[1]], List[List[int]])
True
>>> is_type([[1]], List[int])
False
>>> is_type((1, 1.5), Tuple[int, float])
True
>>> is_type((1, 1.5), Tuple[int])
False

Maybe we should use a custom function instead of using builtin functions, so we can provide one for running on host.

For option two, perhaps we should do something like this: ```python >>> from typing import List, Tuple, get_origin, get_args >>> def is_type(x, T): ... outer = get_origin(T) ... if outer is None: ... outer = T ... if not isinstance(x, outer): ... return False ... if isinstance(x, List): ... return len(x) == 0 or is_type(x[0], get_args(T)[0]) ... if isinstance(x, tuple): ... return len(x) == len(get_args(T)) and ... all([is_type(i, j) for i, j in zip(x, get_args(T))]) ... return True ... >>> is_type([[1]], List[List[int]]) True >>> is_type([[1]], List[int]) False >>> is_type((1, 1.5), Tuple[int, float]) True >>> is_type((1, 1.5), Tuple[int]) False ``` Maybe we should use a custom function instead of using builtin functions, so we can provide one for running on host.

@pca006132 I like this idea and as mentioned, this can be handled well in a simulator.

@pca006132 I like this idea and as mentioned, this can be handled well in a simulator.

Also, will we use list[int] or typing.List[int]? I think the former is legal since Python 3.9 while the latter is used for earlier Python versions but still legal.

Also, will we use `list[int]` or `typing.List[int]`? I think the former is legal since Python 3.9 while the latter is used for earlier Python versions but still legal.
Poster
Owner

Ah right, and it's even deprecated
https://docs.python.org/3/library/typing.html#typing.List
We could do Python 3.9+ only then and list[int].

Ah right, and it's even deprecated https://docs.python.org/3/library/typing.html#typing.List We could do Python 3.9+ only then and ``list[int]``.
pca006132 referenced this issue from a commit 2021-06-09 09:46:07 +08:00
pca006132 referenced this issue from a commit 2021-06-11 13:05:27 +08:00
Sign in to join this conversation.
No Label
No Milestone
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: M-Labs/nac3-spec#15
There is no content yet.