web-dev-qa-db-fra.com

mettre la classe actuelle comme annotation de type de retour

Dans python 3 je peux faire des arguments et retourner des annotations de type. Exemple:

class Graph:
    def __init__(self, V: int, E: int, edges: list):
        pass

    @classmethod
    def fromfile(cls, readobj: type(sys.stdin)):
        pass

    def V(self) -> int:
        pass

    def E(self) -> int:
        pass

Le problème est que je ne peux pas faire d'annotation avec le type de retour de la classe actuelle (Graph), qui n'est pas encore définie. Exemple:

class Graph:
   def reverse(self) -> Graph:
       pass

Ce code s'accompagne d'une erreur

def reverse(self) -> Graph:
NameError: name 'Graph' is not defined

Ces annotations sont vraiment utiles à la fois pour documenter et permettre à IDE de reconnaître les types d'argument et de retour => activer la saisie semi-automatique

UPD: Donc, ce que j'ai trouvé, c'est que c'est impossible ou nécessite des hacks que je n'aime pas, j'ai donc décidé d'utiliser juste def reverse (self) -> 'Graph': ce qui est compréhensible pour la documentation bien qu'il enfreigne la règle. L'inconvénient est que cela ne fonctionne pas pour IDE saisie semi-automatique.

84
sasha.sochka

Alors maintenant, après un certain temps, je peux dire que la décision que j'ai prise utilisait -> 'Graph' au lieu de -> Graph. Cela ne rend pas mon IDE (PyCharm) capable de reconnaître un type de cette façon, mais cela fonctionne juste assez bien à des fins de documentation.

Une autre solution possible que je pouvais utiliser était de changer les annotations au moment de l'exécution, mais cela ne résout pas le problème avec la documentation - vous ne voudrez pas chercher des déclarations de type quelque part au milieu des sources ...

Le problème a ses racines dans la reconnaissance des objets de classe avant que la classe ne soit réellement définie. C'est tout simplement impossible à faire en python.

54
sasha.sochka

En python-3.7, ce problème a été résolu en n'évaluant pas les annotations au moment de la définition de la fonction. Au lieu de cela, ils sont conservés dans __annotations__ sous forme de chaîne. Cela s'appelle Évaluation différée des annotations, introduit dans PEP 56 .

Notez également:

Politique de dépréciation

Commençant par Python 3.7, un __future__ l'importation est requise pour utiliser la fonctionnalité décrite. Aucun avertissement n'est émis.

Dans Python 3.8 un PendingDeprecationWarning est levé par le compilateur en présence d'annotations de type dans les modules sans __future__ import.

À partir de Python 3.9, l'avertissement devient un DeprecationWarning.

Dans Python 4.0, cela deviendra le comportement par défaut. L'utilisation d'annotations incompatibles avec ce PEP n'est plus prise en charge.

Voici un exemple:

In [7]: from __future__ import annotations

In [8]: class C:
   ...:     def func(cls, arg:str) -> C:
   ...:         pass
   ...:     

In [9]: c = C()
31
Kasrâmvd