Como tipos idênticos podem ser incompatíveis no MyPy?

7

Com o seguinte exemplo:

from typing import Callable, Generic, Type, TypeVar

ThetaType = TypeVar('ThetaType', bound=int)
XType = TypeVar('XType', bound=int)


class IteratedFunction(Generic[ThetaType, XType]):

    def find_fixed_point(self,
                         theta: ThetaType,
                         x_init: XType) -> XType:
        return x_init


def combinator(
    iterated_function_cls: Type[
        IteratedFunction[ThetaType, XType]]) -> Callable[
            [IteratedFunction[ThetaType, XType]], XType]:
    old_find_fixed_point = iterated_function_cls.find_fixed_point

    def new_find_fixed_point(
            iterated_function: IteratedFunction[ThetaType, XType],
            theta: ThetaType,
            x_init: XType) -> XType:
        return old_find_fixed_point(iterated_function, theta, x_init)

    return new_find_fixed_point

MyPy diz:

a.py:25: error: Incompatible return value type (got "XType", expected "XType")
a.py:25: error: Argument 1 has incompatible type "IteratedFunction[ThetaType, XType]"; expected "IteratedFunction[ThetaType, XType]"
a.py:25: error: Argument 2 has incompatible type "ThetaType"; expected "ThetaType"
a.py:25: error: Argument 3 has incompatible type "XType"; expected "XType"
a.py:27: error: Incompatible return value type (got "Callable[[IteratedFunction[ThetaType, XType], ThetaType, XType], XType]", expected "Callable[[IteratedFunction[ThetaType, XType]], XType]")
Neil G
fonte
Parece que mypy interpreta new_find_fixed_pointcomo uma função genérica com sua própria instanciação separada de ThetaTypee XType.
user2357112 suporta Monica 19/04
@ user2357112supportsMonica Alguma idéia de como eu poderia corrigi-lo?
Neil G
1
Dê uma olhada em github.com/python/mypy/issues/708 , parece um problema conhecido que não é uma prioridade. Confirme se está relacionado, por favor
Harsha Goli 19/04
1
@HarshaGoli: Isso parece semelhante à primeira vista, mas parece ser uma questão completamente diferente resultante de como os métodos são tratados.
user2357112 suporta Monica 19/04
1
@ NeilG: Eu consideraria pessoalmente um bug ou uma deficiência no mypy.
user2357112 suporta Monica

Respostas:

0

Não tenho certeza se concordo com a premissa desta pergunta.

Aqui está parte do docstring de 3.8

class TypeVar(_Final, _Immutable, _root=True):
    """Type variable.
    Usage::
      T = TypeVar('T')  # Can be anything
      A = TypeVar('A', str, bytes)  # Must be str or bytes

    ....
    def __init__(self, name, *constraints, bound=None,
                 covariant=False, contravariant=False):
    ....

Agora, se você tivesse acabado de

ThetaType = TypeVar('ThetaType')
XType = TypeVar('XType')

você estaria argumentando que os usos do ThetaType devem ser considerados usos do XType, mesmo que 2 tipos de caracteres diferentes tenham sido configurados? Por que adicionar o boundargumento opcional os recolheria automaticamente novamente? A fonte não impõe a presença de um limite, ou qualquer argumento ao lado do nome, de forma alguma.

Eu não acho que seja o trabalho de digitar / mypy inferir suas intenções em declarações de tipo , apenas para verificar seu código x suas intenções de tipo declaradas . Se você deseja que sejam iguais, declare apenas 1 TypeVar. Considerá-los iguais pode perder algum significado semântico se você tiver motivos reais para ter 2.

Vou acrescentar que boundpermite mais flexibilidade do constraintsque corresponde às subclasses. Digamos que você tenha definido 4 subclasses de int. Int1 (int), Int2, Int3, Int4 .... Agora você decidiu particionar seu código onde alguns deles devem aceitar apenas Int1 e Int2. Typevarint12 poderia expressar isso, mesmo que todas as suas subclasses correspondam bound=int.

JL Peyret
fonte
Sim, os dois tipos são diferentes. Eu não acho que isso importe para esta pergunta.
Neil G
1
@ NeilG, talvez você deva modificar sua pergunta para que o título e seus comentários sobre seu código específico que mostra esse comportamento inesperado indiquem por que você está esperando algo diferente. No momento, não vejo nada no bloco de construção TypeVar propriamente dito, indicando por que 2 tipos de caracteres devem se comportar da mesma maneira. Se a maneira como você configurou seu código em torno do TypeVar deve levar à equivalência, explique isso, mas não o fixe apenas no TypeVar .
JL Peyret
Eu nunca disse que os dois tipos de caracteres diferentes deveriam se comportar da mesma maneira. Os erros mostram que cada typevar é incompatível consigo mesmo. É verdade que eu poderia ter encontrado um MWE menor, mas não queria investir mais tempo nisso.
Neil G