J'essaye de diviser ma classe énorme en deux; enfin, essentiellement dans la classe "main" et un mixin avec des fonctions supplémentaires, comme ceci:
main.py
fichier:
import mymixin.py
class Main(object, MyMixin):
def func1(self, xxx):
...
mymixin.py
fichier:
class MyMixin(object):
def func2(self: Main, xxx): # <--- note the type hint
...
Maintenant, bien que cela fonctionne très bien, l'indication de type MyMixin.func2
ne peut bien sûr pas fonctionner. Je ne peux pas importer main.py
, car j'obtiendrais une importation cyclique et sans l'indice, mon éditeur (PyCharm) ne peut pas dire ce que self
c'est.
J'utilise Python 3.4, prêt à passer à 3.5 si une solution y est disponible.
Est-il possible que je puisse diviser ma classe en deux fichiers et conserver toutes les "connexions" afin que mon IDE me propose toujours la complétion automatique et tous les autres avantages qui en découlent en connaissant les types?
self
, car ce sera toujours une sous-classe de la classe actuelle (et tout système de vérification de type devrait être capable de le comprendre seul). Est lafunc2
tentative d'appelfunc1
, qui n'est pas défini dansMyMixin
? Peut-être que cela devrait être (en tant queabstractmethod
, peut-être)?class Main(MyMixin, SomeBaseClass)
que les méthodes de la classe plus spécifique peuvent remplacer celles de la classe de baseRéponses:
Il n'y a pas de moyen extrêmement élégant de gérer les cycles d'importation en général, j'en ai peur. Vos choix sont soit de reconcevoir votre code pour supprimer la dépendance cyclique, soit si ce n'est pas faisable, faites quelque chose comme ceci:
La
TYPE_CHECKING
constante est toujoursFalse
à l'exécution, donc l'importation ne sera pas évaluée, mais mypy (et d'autres outils de vérification de type) évaluera le contenu de ce bloc.Nous devons également transformer l'
Main
annotation de type en une chaîne, en la déclarant effectivement car leMain
symbole n'est pas disponible au moment de l'exécution.Si vous utilisez Python 3.7+, nous pouvons au moins éviter d'avoir à fournir une annotation de chaîne explicite en tirant parti de PEP 563 :
L'
from __future__ import annotations
importation fera de toutes les indications de type des chaînes et ignorera leur évaluation. Cela peut aider à rendre notre code ici légèrement plus ergonomique.Cela dit, l'utilisation de mixins avec mypy nécessitera probablement un peu plus de structure que celle que vous avez actuellement. Mypy recommande une approche qui est essentiellement ce que
deceze
décrit - pour créer un ABC dont votreMain
et vosMyMixin
classes héritent. Je ne serais pas surpris si vous deviez faire quelque chose de similaire pour rendre le vérificateur de Pycharm heureux.la source
typing
, mais PyCharm en était également très satisfaitif False:
.__init__
typing. TYPE_CHECKING
: python.org/dev/peps/pep-0484/#runtime-or-type-checkingPour les personnes aux prises avec des importations cycliques lors de l'importation d'une classe uniquement pour la vérification de type: vous souhaiterez probablement utiliser une référence directe (PEP 484 - Indices de type):
Donc au lieu de:
tu fais:
la source
File -> Invalidate Caches
?if False:
vous pouvez aussifrom typing import TYPE_CHECKING
etif TYPE_CHECKING:
.Le plus gros problème est que vos types ne sont pas sains d'esprit au départ.
MyMixin
fait une hypothèse codée en dur dans laquelle il sera mélangéMain
, alors qu'il pourrait être mélangé dans n'importe quel nombre d'autres classes, auquel cas il se briserait probablement. Si votre mixin est codé en dur pour être mélangé dans une classe spécifique, vous pouvez aussi bien écrire les méthodes directement dans cette classe au lieu de les séparer.Pour faire cela correctement avec un typage sain,
MyMixin
doit être codé par rapport à une interface ou à une classe abstraite dans le langage Python:la source
Il s'avère que ma tentative initiale était également assez proche de la solution. Voici ce que j'utilise actuellement:
Notez l'
if False
instruction import within qui n'est jamais importée (mais IDE le sait de toute façon) et utilisez laMain
classe comme chaîne car elle n'est pas connue au moment de l'exécution.la source
Je pense que le moyen idéal devrait être d'importer toutes les classes et dépendances dans un fichier (comme
__init__.py
), puisfrom __init__ import *
dans tous les autres fichiers.Dans ce cas, vous êtes
la source
import *
, et vous pouvez toujours profiter de cette approche facile