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.
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
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:
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).
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]: ...
Recommended Posts