代码之家  ›  专栏  ›  技术社区  ›  juanpa.arrivillaga

具有值限制和联合/可选联合的mypy错误TypeVar无法传递泛型容器类型

  •  2
  • juanpa.arrivillaga  · 技术社区  · 6 年前

    所以,下面的例子显然是人为的,但我试图保持一些真实性,以我的实际情况。现在我已经缩减了这个,我确信我遗漏了一些明显的东西。考虑两种类型和限制性联盟:

    from typing import Union, TypeVar, Optional, Generic, overload
    
    class Foo:
        def __init__(self, x: int)-> None:
            self.x = x
        def frobnicate(self) -> 'Foo':
            return Foo((self.x + 42) // 42)
    
    class Bar:
        def __init__(self, y: int) -> None:
            self.y = y
        def frobnicate(self) -> 'Bar':
            return Bar(self.y + 88)
    
    MyType = TypeVar('MyType', Foo, Bar)
    class Container(Generic[MyType]):
        val: Optional[MyType]
        def __init__(self, val: Optional[MyType]=None) -> None:
            self.val = val
    
    def transmogrify(arg: Optional[MyType]) -> Optional[MyType]:
        if arg is None:
            return None
        else:
            return arg.frobnicate()
    
    def extract_stuff(x: Optional[int], cont: Container[MyType]) -> Optional[MyType]:
        result: Optional[MyType]
        if x is None:
            result = None
        elif x == 88 or x == 42:
            result = transmogrify(cont.val)
        else:
            result = cont.val
        return result
    

    当我尝试使用mypy键入check this时,会出现以下错误:

    mcve3.py:32: error: Value of type variable "MyType" of "transmogrify" cannot be "Optional[Foo]"
    mcve3.py:32: error: Value of type variable "MyType" of "transmogrify" cannot be "Optional[Bar]"
    

    我无法理解这一点。我怀疑这是许多嵌套联合的问题?注意,在我的实际代码中,我使用的是自定义单例枚举 Null ,所以无论你在哪里看到 Optional[Something] 实际上是 Union[Something, Null] ,但我不认为这有什么区别。

    Optional ,即。 Union ,一切都很好:

    from typing import Union, TypeVar, Optional, Generic, overload
    
    class Foo:
        def __init__(self, x: int)-> None:
            self.x = x
        def frobnicate(self) -> 'Foo':
            return Foo((self.x + 42) // 42)
    
    class Bar:
        def __init__(self, y: int) -> None:
            self.y = y
        def frobnicate(self) -> 'Bar':
            return Bar(self.y + 88)
    
    MyType = TypeVar('MyType', Foo, Bar)
    class Container(Generic[MyType]):
        val: MyType
        def __init__(self, val: MyType) -> None:
            self.val = val
    
    def transmogrify(arg: MyType) -> MyType:
        if arg is None:
            return None
        else:
            return arg.frobnicate()
    
    def extract_stuff(x: int, cont: Container[MyType]) -> MyType:
        if x is None:
            return None
        elif x == 88 or x == 42:
            return transmogrify(cont.val)
        else:
            return cont.val
    

    注意,我已经尝试抽象出一个基类 Foo Bar 从抽象基类派生 class MyType(metaclass=abc.Meta) ,但会弹出一个非常类似的错误。

    编辑以添加:

    (py37) Juans-MBP: juan$ mypy --version
    mypy 0.620
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   Michael0x2a    6 年前

    这似乎是mypy最近修复的一个bug。我可以使用mypy 0.630在您的第一个代码片段中重新编写问题,但无法在master上同时使用mypy 0.641和mypy的最新版本重新编写。

    我毫不怀疑这个bug是由 https://github.com/python/mypy/pull/5699

    你可以监视 mypy's blog 如果您希望收到未来版本的通知,以避免将来出现类似情况。新版本大约每6周到两个月左右发布一次下一个版本预计将在撰写本文后大约两周左右发布。