python / python/typing

Assignability to a Protocol Using `Self` Must Respect Variance

Ouverte
#2,051 2 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

topic: typing spec
Langage dominant
Python
Étoiles
1.8k
Forks
302
Merge moyen
23 h
PR mergées (30 j)
8

Description

I just stumbled across this paragraph:

https://github.com/python/typing/blob/2d88da2a407b556f5b52b4c6ad1bd659873bb9ac/docs/spec/generics.rst?plain=1#L2540-L2544

If I understand it correctly, then the following code is fine, i.e., Foo is assignable to Proto according to the explanation:

from __future__ import annotations

from typing import Protocol, Self


class Proto(Protocol):
    def f(self, x: Self) -> None: ...


class Foo:
    def f(self, x: Sub) -> None:
        pass


class Sub(Foo):
    pass


x: Proto = Foo()

However, type checkers like mypy and pyright reject this code. This aligns with my expectation: If I have an instance x: Proto, then I should be able to call x.f(x). But for y: Foo, I cannot call y.f(y).

The paragraph in question should distinguish between covariant, contravariant, and invariant occurences of Self:

from __future__ import annotations

from typing import Protocol, Self


class Proto(Protocol):
    def f(self, x: Self) -> None: ...  # contravariant
    def g(self, x: Self) -> Self: ...  # x: contravariant, return type: covariant
    def h(self, x: list[Self]) -> None: ...  # invariant


class Sup:
    pass


class Foo(Sup):
    def f(self, x: Sup) -> None:  # x can be of type Foo or any superclass
        pass

    def g(self, x: Sup) -> Sub:  # return type can be Foo or any subclass
        raise RuntimeError()

    def h(self, x: list[Foo]) -> None:  # no sub-/superclass allowed as argument to list
        pass


class Sub(Foo):
    pass


x: Proto = Foo()  # OK, also according to mypy and pyright

I assume that all the uses of Self are valid in this example, at least mypy and pyright do not complain and I couldn’t find any statement that would restrict Self in protocols to covariant positions or even return types only. Maybe it also makes sense to adjust the example after the paragraph in question. Currently, it only uses Self in a return type.

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par docs/spec/generics.rst aux lignes liées 2540-2544 et examinez la discussion environnante sur Self dans les protocoles. Exécutez les exemples fournis avec mypy et pyright, puis mettez à jour le paragraphe et l’exemple voisin afin d’expliquer les utilisations contravariantes, covariantes et invariantes de Self ; le travail est terminé lorsque la spécification correspond au comportement démontré par les vérificateurs.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
documentation
Type d'issue
Documentation
Difficulté
4/5
Temps estimé
3-5 jours
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
38/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.