Общий суперкласс «не определен», несмотря на то, что mypy счастлив

#python #generics #mypy

Вопрос:

Я боролся со странными ситуациями, когда mypy счастлив, но python выходит из строя, когда я запускаю код. Вот проблема, с которой я сталкиваюсь с дженериками. У меня есть два файла в одном каталоге. Когда я запускаю python3 sample_parser.py , я получаю следующую ошибку:

 Traceback (most recent call last):
  File "/Users/joe/repos/ut-norm-james/so_generics/sample_parser.py", line 8, in <module>
    class SampleParser(LookaheadParser[str]):
NameError: name 'LookaheadParser' is not defined
 

Вот lookahead_parser.py :

 from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from typing import TypeVar, Generic, Optional, Callable


_T = TypeVar("_T")
StateFunc = Callable[[_T], Callable]


class LookaheadParser(Generic[_T]):
    def __init__(self):
        self._token_index: int = 0
        self._tokens: list[_T] = []
        self._state: StateFunc

    def _parse(self) -> None:
        while self._token_index < len(self._tokens):
            self._state = self._state(self._tokens[self._token_index])
            self._token_index  = 1

    def _lookahead(self, offset: int) -> Optional[_T]:
        prospective_index = self._token_index   offset
        if prospective_index < len(self._tokens):
            return self._tokens[prospective_index]
        return None

    def _advance(self, offset: int) -> None:
        self._token_index  = offset
 

Вот sample_parser.py :

 from __future__ import annotations
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from .lookahead_parser import LookaheadParser, StateFunc


class SampleParser(LookaheadParser[str]):
    def __init__(self, raw_text: str):
        self._raw_text = raw_text
        self._state = self._state_first

    def parse(self) -> None:
        self._parse()

    def _state_first(self, token: str) -> StateFunc:
        pass  # stub


if __name__ == "__main__":
    pass  # stub
 

Я запускаю Python 3.9.6, но это также происходило в 3.9.5. Проблема возникает независимо от того , использую ли я _T или T , если вы косо на это смотрите. сама mypy не сообщает о каких-либо проблемах.

Ответ №1:

Вы импортируете только lookahead_parser в том случае, если TYPE_CHECKING это правда. Эта переменная имеет значение false во время выполнения, поэтому модуль никогда не загружается. Просто удалите if TYPE_CHECKING: деталь и выполните импорт безоговорочно.

 from .lookahead_parser import LookaheadParser, StateFunc
 

Комментарии:

1. Икса! Спасибо! Я должен был это предвидеть. Но теперь я получаю TypeVar не определено, когда я запускаю python. Похоже, что flake8 и mypy недостаточно, чтобы сказать мне, есть ли в коде необходимые определения. Я запускаю VSCode, потому что PyCharm плохо справлялся с подсказками типа.

2. Удаление всего импорта из TYPE_CHECKING решило эту проблему. Я просто хотел бы, чтобы мне рассказали об этих проблемах до выполнения. Спасибо за вашу помощь!

3. Просто пока избегайте переменной TYPE_CHECKING . Это позволяет вам выполнять сложные трюки с метапрограммированием и обходить проверку типов, и я сомневаюсь, что вам все равно понадобится что-то из этого.

4. Я нахожу, что все мои другие проблемы с использованием типов решаются путем извлечения импорта из проверки типов. Я начал использовать проверку ТИПОВ, чтобы обойти очевидные циклические зависимости, используя типы в PyCharm. Похоже, мне следовало прекратить использовать проверку типов, когда я переключился на VSCode и mypy, так как подсказки типа теперь, похоже, ведут себя так, как описано в документах. Еще раз спасибо!

5. Мне действительно пришлось добавить if TYPE_CHECKING несколько модулей, но, по крайней мере, теперь это имеет смысл-каждый из этих модулей включал в себя другой.