2016-11-07 3 views
2

Le module typing de Python définit un nombre de types de canard, par exemple, typing.SupportsAbs pour représenter tout type qui implémente la méthode spéciale __abs__.Annotation de type Python pour le type de canard personnalisé

Est-il possible de définir des types de canard personnalisés d'une manière telle que je puisse les utiliser comme des annotations de type valides?

Par exemple, je voudrais pouvoir annoter qu'un argument doit être un équivalent de type canard d'un threading.Lock, à savoir, tout objet qui implémente acquire et release méthodes. Idéalement, je pourrais annoter un tel argument comme SupportsAcquireAndRequire ou DuckLock, plutôt que object.

+0

Avez-vous regardé comment ils sont définis? Vous pourriez faire quelque chose de similaire assez facilement. – jonrsharpe

+0

En effet, 'SupportsAbs' ne contient que quelques lignes de code héritées du 'typing._Protocol' privé. Y at-il un moyen de faire cela qui n'implique pas d'utiliser une API privée? – shoyer

Répondre

4

Vous pouvez définir un abstract base class (ABC) pour spécifier l'interface:

from abc import ABCMeta, abstractmethod 

class SupportsAcquireAndRequire(metaclass=ABCMeta): 
    @abstractmethod 
    def acquire(self): 
     pass 

    @abstractmethod 
    def release(self): 
     pass 

    @classmethod 
    def __subclasshook__(cls, C): 
     for method in ('release', 'acquire'): 
      for B in C.__mro__: 
       if method in B.__dict__: 
        if B.__dict__[method] is None: 
         return NotImplemented 
        break 
      else: 
       return NotImplemented 
     return True 

C'est fondamentalement la façon dont les protocoles (comme typing.SupportsAbs) sont mises en œuvre, mais sans directement à l'aide ABCMeta.

En donnant l'ABC un __subclasshook__ method, vous pouvez l'utiliser dans isinstance() et issubclass() tests, ce qui est plus assez bon pour des outils tels que mypy:

>>> from threading import Lock 
>>> isinstance(Lock(), SupportsAcquireAndRequire) 
True 
+1

On dirait que c'est à peu près le meilleur que nous pouvons faire pour l'instant - c'est en fait toujours un problème ouvert pour «tapant»: https://github.com/python/typing/issues/11 – shoyer

+0

@shoyer: oui, qui est pourquoi la documentation mypy que j'ai liée à mentionne qu'un soutien plus explicite pour le typage du canard est encore à venir. Jusque-là, ABCMeta est la voie à suivre. –