J'ai lu PEP-544 (Protocoles: sous-typage structurel (typage statique du canard))

J'ai décidé de lire PEP 544 --Protocols: Sous-typage structurel (typage statique du canard) dans le flux d'une discussion, donc la mienne Prenez note de votre compréhension.

Aperçu

approche

Définition du protocole

Une classe qui hérite de typing.Protocol est appelée une classe de protocole (ou simplement un protocole). En tant que membre du protocole, quel type et quel type de membre (variable, méthode) peut être défini dans la classe de protocole.

L'exemple suivant définit le protocole SupportsClose, qui" a une méthode appelée close () sans arguments et sans valeur de retour.

from typing import Protocol

class SupportsClose(Protocol):
    def close(self) -> None:
        pass

Par exemple, on peut dire que la classe suivante respecte le protocole SupportsClose.

class Resource:
    ...
    def close(self) -> None:
        self.file.close()
        self.lock.release()

Par conséquent, le code suivant est vérifié de type comme prévu.

def close_all(things: Iterable[SupportsClose]) -> None:
    for t in things:
        t.close()

f = open('foo.txt')
r = Resource()
close_all([f, r])  # OK!
close_all([1])     # Error: 'int' has no 'close' method

Définition des membres du protocole (variables)

Les variables peuvent être définies comme membres du protocole à l'aide d'annotations de variables. Notez que si vous initialisez une variable dans une méthode, ce ne sera pas un membre du protocole, donc self.temp dans le code ci-dessous sera ignoré (cela n'affectera pas la vérification du type de protocole).

from typing import Protocol, List

class Template(Protocol):
    name: str        # This is a protocol member
    value: int = 0   # This one too (with default)

    def method(self) -> None:
        self.temp: List[int] = [] # Error in type checker

Au fait, pour les variables de classe, utilisez typing.ClassVar [^ 1].

[^ 1]: J'ai essayé d'expérimenter à portée de main, mais ça ne marche pas ...?: Pensée:

Héritage de classe de protocole

Jusqu'à présent, nous avons expliqué que la classe de protocole est traitée comme un type (annotation de type), mais puisque la classe de protocole est une classe Python normale, elle peut être héritée pour créer une classe dérivée.

class PColor(Protocol):
    @abstractmethod
    def draw(self) -> str:
        ...
    def complex_method(self) -> int:
        # some complex code here

class NiceColor(PColor):
    def draw(self) -> str:
        return "deep blue"

S'ils sont hérités, les membres sont hérités par la classe dérivée tels quels, donc bien sûr, il est considéré comme satisfaisant le protocole [^ 2].

Si vous ne faites que vérifier le type, vous n'avez pas besoin d'en hériter, il semble donc bon de penser que le partage de l'implémentation est un avantage lors de l'utilisation de cette méthode. Un exemple de son utilisation en combinaison avec ʻabc.abstractmethod` est également présenté, et c'est une introduction semblable à ABC (classes de base abstraites) [^ 3].

[^ 2]: Il est possible de le surcharger avec une classe dérivée afin qu'elle ne satisfasse pas le protocole, mais comme il s'agit d'un usage irrégulier, l'explication est omise. [^ 3]: Ou plutôt, le comportement autre que l'indication de type semble être presque équivalent à ABC (à l'exécution).

Protocole de rappel

Il a dit qu'il serait bien d'utiliser une classe de protocole avec une méthode __call__ () pour représenter des interfaces appelables complexes telles que des arguments variables, des surcharges et des génériques. Cela semble pratique.

from typing import Optional, List, Protocol

class Combiner(Protocol):
    def __call__(self, *vals: bytes,
                 maxlen: Optional[int] = None) -> List[bytes]: ...

Impressions

Recommended Posts

J'ai lu PEP-544 (Protocoles: sous-typage structurel (typage statique du canard))
J'ai lu PEP 560 (support de base pour le module de saisie et les types génériques)
J'ai lu PEP 613 (alias de type explicite)
J'ai lu PEP 612 (Variables de spécification des paramètres)
J'ai lu PEP 604 (syntaxe complémentaire pour Union []).
J'ai lu PEP-362 (objet de signature de fonction)
J'ai lu PEP 618 (Ajouter une vérification de longueur facultative à la fermeture éclair)
J'ai lu PEP 584 (Add Union Operators To dict)
J'ai lu PEP 614 (Relaxing Grammar Restrictions on Decorators)
J'ai lu PEP-593 (fonction flexible et annotations variables)