top | item 45403103

(no title)

thr0w4w4y1337 | 5 months ago

from typing import Protocol, TypeVar

T_co = TypeVar("T_co", covariant=True)

class Indexable(Protocol[T_co]): def __getitem__(self, i: int) -> T_co: ...

def f(x: Indexable[str]) -> None: print(x[0])

I am failing to format it proprely here, but you get the idea.

discuss

order

whilenot-dev|5 months ago

Just fyi: https://news.ycombinator.com/formatdoc

> Text after a blank line that is indented by two or more spaces is reproduced verbatim. (This is intended for code.)

If you'd want monospace you should indent the snippet with two or more spaces:

  from typing import Protocol, TypeVar
  
  T_co = TypeVar("T_co", covariant=True)
  
  class Indexable(Protocol[T_co]):
    def __getitem__(self, i: int) -> T_co: ...
  
  def f(x: Indexable[str]) -> None:
    print(x[0])

amluto|5 months ago

I give Rust a lot of points for putting control over covariance into the language without making anyone remember which one is covariance and which one is contravariance.

sevensor|5 months ago

One of the things that makes typing an existing codebase difficult in Python is dealing with variance issues. It turns out people get these wrong all over the place in Python and their code ends up working by accident.

Generally it’s not worth trying to fix this stuff. The type signature is hell to write and ends up being super complex if you get it to work at all. Write a cast or Any, document why it’s probably ok in a comment, and move on with your life. Pick your battles.

ndriscoll|5 months ago

Co- means with. Contra- means against. There are lots of words with these prefixes you could use to remember (cooperate, contradict, etc.).

matusp|5 months ago

There is also bunch of prepackaged types, such as collections.abc.Sequence that could be used in this case.

thr0w4w4y1337|5 months ago

Sequence does not cut it, since the op mentioned int indexed dictionaries. But yeah.

dragonwriter|5 months ago

As of Python 3.12, you don’t need separately declared TypeVars with explicit variance specifications, you can use the improved generic type parameter syntax and variance inference.

So, just:

  class Indexable[T](Protocol):
    def __getitem__(self, i: int,/) -> T: ... 
is enough.