Wie können identische Typen in MyPy nicht kompatibel sein?

7

Mit folgendem Beispiel:

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 sagt:

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.
quelle
Es sieht so aus, new_find_fixed_pointals würde mypy als generische Funktion mit einer eigenen separaten Instanziierung von ThetaTypeund interpretiert XType.
user2357112 unterstützt Monica
@ user2357112supportsMonica Irgendeine Idee, wie ich das beheben könnte?
Neil G
1
Werfen Sie einen Blick auf github.com/python/mypy/issues/708 , scheint ein bekanntes Problem zu sein, das keine Priorität hat. Bestätigen Sie bitte, ob es verwandt ist
Harsha Goli
1
@HarshaGoli: Das sieht auf den ersten Blick ähnlich aus, aber es scheint ein völlig anderes Problem zu sein, das sich aus dem Umgang mit Methoden ergibt.
user2357112 unterstützt Monica
1
@NeilG: Ich persönlich würde es entweder als Fehler oder als Mangel an Mypy betrachten.
user2357112 unterstützt Monica

Antworten:

0

Ich bin mir nicht sicher, ob ich der Prämisse dieser Frage zustimme.

Hier ist ein Teil des Docstrings von 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):
    ....

Nun, wenn Sie nur hatten

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

Würden Sie argumentieren, dass die Verwendung von ThetaType als Verwendung von XType betrachtet werden sollte, obwohl 2 verschiedene Typevars eingerichtet wurden? Warum würde das Hinzufügen des boundoptionalen Arguments sie automatisch wieder zusammenfassen? Die Quelle erzwingt in keiner Weise das Vorhandensein von gebundenen oder anderen Argumenten neben dem Namen.

Ich glaube nicht, dass es die Aufgabe von typing / mypy ist, Ihre Absichten in Typdeklarationen abzuleiten , nur um Ihren Code mit Ihren deklarierten Typabsichten zu vergleichen . Wenn Sie meinen, dass sie gleich sind, deklarieren Sie nur 1 TypeVar. Wenn Sie sie als gleich betrachten, könnte dies eine semantische Bedeutung verlieren, wenn Sie tatsächlich Gründe hätten, 2 zu haben.

Ich werde hinzufügen, dass dies boundmehr Flexibilität ermöglicht, constraintsals es für Unterklassen gilt. Angenommen, Sie haben 4 Unterklassen von int benutzerdefiniert. Int1 (int), Int2, Int3, Int4 ... Jetzt haben Sie beschlossen, Ihren Code so zu partitionieren, dass ein Teil davon nur Int1 und Int2 akzeptieren sollte. Typevarint12 könnte dies etwas ausdrücken, obwohl alle Ihre Unterklassen übereinstimmen bound=int.

JL Peyret
quelle
Ja, die beiden Typen sind unterschiedlich. Ich denke nicht, dass es für diese Frage wichtig ist.
Neil G
1
@NeilG dann sollten Sie vielleicht Ihre Frage so ändern, dass der Titel und Ihre Kommentare zu Ihrem bestimmten Code, der dieses unerwartete Verhalten zeigt, anzeigen, warum Sie etwas anderes erwarten. Im Moment sehe ich im TypeVar-Baustein selbst nichts, was darauf hinweist, warum sich 2 Typevars gleich verhalten sollten. Wenn die Art und Weise, wie Sie Ihren Code um TypeVar einrichten, zu Äquivalenz führen sollte, erklären Sie dies bitte, aber hängen Sie ihn nicht nur an TypeVar an .
JL Peyret
Ich habe nie gesagt, dass sich die beiden verschiedenen Typevars gleich verhalten sollten. Die Fehler zeigen, dass jeder Typevar mit sich selbst nicht kompatibel ist. Es ist wahr, dass ich vielleicht eine kleinere MWE hätte finden können, aber ich wollte nicht mehr Zeit in diese investieren.
Neil G