Type annotation for slice
![](https://secure.gravatar.com/avatar/6b48c15a6e5f9f8076bdc23fde5a54a0.jpg?s=120&d=mm&r=g)
(it is formerly discussed in https://discuss.python.org/t/is-it-a-good-practice-to-pass-tuple-of-slice-to... ) Currently we cannot write type annotation for slice like `slice[str, str]`. And it is useful when write something like `a["C1":"C2"]` , which is used in pandas already. And I also want to write something like `a[(1,2):4,(5,6):9]` which type could be `tuple[slice[tuple[int, int], int, None], ...]` So I think it would be better if slice support type annotation
![](https://secure.gravatar.com/avatar/047f2332cde3730f1ed661eebb0c5686.jpg?s=120&d=mm&r=g)
Currently the builtins.pyi stub file has the following definition for `slice`: ```py class slice(object): start: Any step: Any stop: Any @overload def __init__(self, stop: Any) -> None: ... @overload def __init__(self, start: Any, stop: Any, step: Any = ...) -> None: ... __hash__: None # type: ignore def indices(self, len: int) -> Tuple[int, int, int]: ... ``` Would you want it to have a single type parameter, so start/stop/step should all have the same type, or do you think there's a need to specify their types separately? The simplest improvement I could think of would use a single type parameter, be something like ```py class slice(Generic[T]): start: Optional[T] step: Optional[T] stop: Optional[T] @overload def __init__(self, stop: Optional[T]) -> None: ... @overload def __init__(self, start: Optional[T] , stop: Optional[T] , step: Optional[T] = ...) -> None: ... __hash__: None # type: ignore def indices(self, len: int) -> Tuple[int, int, int]: ... ``` Note that the `indices()` method is only useful if T is int. I wouldn't be surprised if there were additional pitfalls though -- I don't have much experience myself with non-numeric indexes. On Thu, Dec 10, 2020 at 11:01 AM Hao Zhang via Typing-sig < typing-sig@python.org> wrote:
(it is formerly discussed in https://discuss.python.org/t/is-it-a-good-practice-to-pass-tuple-of-slice-to... )
Currently we cannot write type annotation for slice like `slice[str, str]`.
And it is useful when write something like `a["C1":"C2"]` , which is used in pandas already.
And I also want to write something like `a[(1,2):4,(5,6):9]` which type could be `tuple[slice[tuple[int, int], int, None], ...]`
So I think it would be better if slice support type annotation _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: guido@python.org
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>
![](https://secure.gravatar.com/avatar/57da4d2e2a527026baaaab35e6872fa5.jpg?s=120&d=mm&r=g)
There's an old open issue about this: https://github.com/python/typing/issues/159. It doesn't look like there's a strong reason not to do it, just that so far nobody has cared enough to put in the work and fix it. One complexity is figuring out how many type parameters there should be. El jue, 10 dic 2020 a las 11:21, Guido van Rossum (<guido@python.org>) escribió:
Currently the builtins.pyi stub file has the following definition for `slice`: ```py class slice(object): start: Any step: Any stop: Any @overload def __init__(self, stop: Any) -> None: ... @overload def __init__(self, start: Any, stop: Any, step: Any = ...) -> None : ... __hash__: None # type: ignore def indices(self, len: int) -> Tuple[int, int, int]: ... ``` Would you want it to have a single type parameter, so start/stop/step should all have the same type, or do you think there's a need to specify their types separately?
The simplest improvement I could think of would use a single type parameter, be something like ```py class slice(Generic[T]): start: Optional[T] step: Optional[T] stop: Optional[T] @overload def __init__(self, stop: Optional[T]) -> None: ... @overload def __init__(self, start: Optional[T] , stop: Optional[T] , step: Optional[T] = ...) -> None: ... __hash__: None # type: ignore def indices(self, len: int) -> Tuple[int, int, int]: ... ``` Note that the `indices()` method is only useful if T is int.
I wouldn't be surprised if there were additional pitfalls though -- I don't have much experience myself with non-numeric indexes.
On Thu, Dec 10, 2020 at 11:01 AM Hao Zhang via Typing-sig < typing-sig@python.org> wrote:
(it is formerly discussed in https://discuss.python.org/t/is-it-a-good-practice-to-pass-tuple-of-slice-to... )
Currently we cannot write type annotation for slice like `slice[str, str]`.
And it is useful when write something like `a["C1":"C2"]` , which is used in pandas already.
And I also want to write something like `a[(1,2):4,(5,6):9]` which type could be `tuple[slice[tuple[int, int], int, None], ...]`
So I think it would be better if slice support type annotation _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: guido@python.org
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...> _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: jelle.zijlstra@gmail.com
![](https://secure.gravatar.com/avatar/6b48c15a6e5f9f8076bdc23fde5a54a0.jpg?s=120&d=mm&r=g)
To be more sematic, there should be only one parameter, because it is "slice". But in my case, I want to save a `{}` when passing `dict[tuple[int, int], int]` to `__getitem__` so I want it to be three different type parameters. Since `__getitem__` will treat colon only as slice, I think maybe slice has responsibility to be more generic?
![](https://secure.gravatar.com/avatar/047f2332cde3730f1ed661eebb0c5686.jpg?s=120&d=mm&r=g)
On Thu, Dec 10, 2020 at 11:54 AM Hao Zhang via Typing-sig < typing-sig@python.org> wrote:
To be more sematic, there should be only one parameter, because it is "slice".
But in my case, I want to save a `{}` when passing `dict[tuple[int, int], int]` to `__getitem__` so I want it to be three different type parameters.
Can you show some examples of what you mean here? It looks like you are talking about ``` key = {(1,2):3} d[key] ``` but there's no slice there.
Since `__getitem__` will treat colon only as slice, I think maybe slice has responsibility to be more generic?
Can you clarify this too? -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>
![](https://secure.gravatar.com/avatar/6b48c15a6e5f9f8076bdc23fde5a54a0.jpg?s=120&d=mm&r=g)
Can you show some examples of what you mean here?
It needs a little more background to explain why I want to use something like `d[{(1,2): 3}]`, let me change another easier example. Now I have a named tensor where there is a str as name for every index. such as a normal 2*3*4 tensor `T`(2*3*4 tensor means it is something like `float[2][3][4]`), whose three index has name `i` and `j` and `k`. set `i=0, j=2, k=1`, and I will get `T[0, 2, 1]`. In my application, it is difficult to tell the index order, because transpose is very frequent in many other operations. So I have to use `T[{"i": 0, "j": 2, "k": 1}]` to get the item from so-called "named tensor". Then when tensor `T` is transposed into a 2*4*3 tensor `G`, I can also use the same expression above to get the same item(`T[{"i": 0, "j": 2, "k": 1}] == G[{"i": 0, "j": 2, "k": 1}] == T[0, 2, 1] == G[0, 1, 2]`) I think `T[{"i": 0, "j": 2, "k": 1}]` is a little wordy, If I can use `T["i": 0, "j": 2, "k": 1]` directly, it would be better. And luckly, it is valid syntax in python so I can use it now, python treats it as `tuple[slice, ...]` where each slice is something like `slice[str, int, None]`. But sadly I cannot describe such detail for slice in type annotation as `slice[str, int, None]`, that is why I post this thread.
Can you clarify this too?
In python colon in `d[x:y]` is always treated as slice, but sometimes it may not means "slice of list", just like the example above. So I think maybe slice should support three parameters rather than single paramter.
![](https://secure.gravatar.com/avatar/047f2332cde3730f1ed661eebb0c5686.jpg?s=120&d=mm&r=g)
Your use of slices definitely looks like a hack. :-) I'm not sure I would want to legitimize that use case by complicating the parameters for slice[]. It might be better for you to wait for PEP 637, then you can write `T[i=0, j=2, k=1]`. Are there other uses you are aware of where slices are not homogeneous in type? If this is rare we could just tell users to use `Any` or a union, while simplifying life for other users -- types with multiple parameters are harder to remember (e.g. I can never remember what the three parameters to Generator mean :-). Maybe you can just open an issue for the typeshed repo to add a single type parameter to the slice class? The default would be `Any` so existing uses of `slice` without parameters would mean the same thing as they currently mean (start, stop and step all have type `Any`). On Fri, Dec 11, 2020 at 11:37 AM Hao Zhang via Typing-sig < typing-sig@python.org> wrote:
Can you show some examples of what you mean here?
It needs a little more background to explain why I want to use something like `d[{(1,2): 3}]`, let me change another easier example.
Now I have a named tensor where there is a str as name for every index. such as a normal 2*3*4 tensor `T`(2*3*4 tensor means it is something like `float[2][3][4]`), whose three index has name `i` and `j` and `k`. set `i=0, j=2, k=1`, and I will get `T[0, 2, 1]`.
In my application, it is difficult to tell the index order, because transpose is very frequent in many other operations. So I have to use `T[{"i": 0, "j": 2, "k": 1}]` to get the item from so-called "named tensor". Then when tensor `T` is transposed into a 2*4*3 tensor `G`, I can also use the same expression above to get the same item(`T[{"i": 0, "j": 2, "k": 1}] == G[{"i": 0, "j": 2, "k": 1}] == T[0, 2, 1] == G[0, 1, 2]`)
I think `T[{"i": 0, "j": 2, "k": 1}]` is a little wordy, If I can use `T["i": 0, "j": 2, "k": 1]` directly, it would be better. And luckly, it is valid syntax in python so I can use it now, python treats it as `tuple[slice, ...]` where each slice is something like `slice[str, int, None]`. But sadly I cannot describe such detail for slice in type annotation as `slice[str, int, None]`, that is why I post this thread.
Can you clarify this too?
In python colon in `d[x:y]` is always treated as slice, but sometimes it may not means "slice of list", just like the example above. So I think maybe slice should support three parameters rather than single paramter. _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: guido@python.org
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>
![](https://secure.gravatar.com/avatar/6b48c15a6e5f9f8076bdc23fde5a54a0.jpg?s=120&d=mm&r=g)
Well, PEP 637 looks great. I agree that this situation is too rare, so maybe single parameter is a better choice. If you are interested, let me share a complicated example :-) I have a class which contains something like a finite square lattice(such as a 4x4 lattice who owns 16 sites), and there is a huge-rank "tensor" to decsribe it, with one index for every sites, for 4x4 lattice, it is a 2x2x2x2x2x2x2x2x2x2x2x2x2x2x2x2 tensor(16-rank). With the same thought in the previous example, I use `tuple[int, int]` to specify the index of this big tensor to get item or to get something like "slice of tensor", look like: ``` result = A[{(1,1): 1, (1,2): 0}] ``` This is a sliced tensor which rank is 16-2=14, since two of 16 index in tensor A are fixed. Just like this in numpy ``` result = A[:, :, :, :, :, 1, 0, :, :, :, :, :, :, :, :, :] ``` Don't worry about complexity of this "tensor", I am no using dense tensor to store it, I am using a network(a tensor network) to approximate this huge-rank tensor, although I want to treat it more like a normal tensor. PEP 637 cannot be used in this case, but maybe I should not use `__getitem__` here?
![](https://secure.gravatar.com/avatar/047f2332cde3730f1ed661eebb0c5686.jpg?s=120&d=mm&r=g)
Yeah, no matter what you do that example will look ugly. :-) I'm not sure what the (1, 1) and (1, 2) in your example stand for (I'm not familiar with your field), but it appears these index the 5th and 6th (base 0) dimension? It does sound like you're better off defining a custom function to make this notation more manageable. Maybe A.slice((1, 1, 1), (1, 2, 0))? On Fri, Dec 11, 2020 at 8:57 PM Hao Zhang via Typing-sig < typing-sig@python.org> wrote:
Well, PEP 637 looks great.
I agree that this situation is too rare, so maybe single parameter is a better choice.
If you are interested, let me share a complicated example :-)
I have a class which contains something like a finite square lattice(such as a 4x4 lattice who owns 16 sites), and there is a huge-rank "tensor" to decsribe it, with one index for every sites, for 4x4 lattice, it is a 2x2x2x2x2x2x2x2x2x2x2x2x2x2x2x2 tensor(16-rank). With the same thought in the previous example, I use `tuple[int, int]` to specify the index of this big tensor to get item or to get something like "slice of tensor", look like:
``` result = A[{(1,1): 1, (1,2): 0}] ```
This is a sliced tensor which rank is 16-2=14, since two of 16 index in tensor A are fixed. Just like this in numpy
``` result = A[:, :, :, :, :, 1, 0, :, :, :, :, :, :, :, :, :] ```
Don't worry about complexity of this "tensor", I am no using dense tensor to store it, I am using a network(a tensor network) to approximate this huge-rank tensor, although I want to treat it more like a normal tensor.
PEP 637 cannot be used in this case, but maybe I should not use `__getitem__` here? _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: guido@python.org
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>
![](https://secure.gravatar.com/avatar/6b48c15a6e5f9f8076bdc23fde5a54a0.jpg?s=120&d=mm&r=g)
Hmm, sites in a 4x4 lattice is labeled like this: ``` (0,0) (0,1) (0,2) (0,3) (1,0) (1,1) (1,2) (1,3) (2,0) (2,1) (2,2) (2,3) (3,0) (3,1) (3,2) (3,3) ``` and (1, 1) and (1, 2) just means that two site in this lattice. it is the 5th and 6th dimension after flatten the lattice. Maybe I should use something like A.slice({(1,1):1, (1,2):0}), I think. Thank you very much
participants (3)
-
Guido van Rossum
-
Hao Zhang
-
Jelle Zijlstra