Итак, следующий пример явно надуманный, но я попытался сохранить правдоподобие моей реальной ситуации.Теперь, когда я сократил это, я уверен, что упускаю что-то очевидное.Рассмотрим пару типов и ограниченный союз:
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, я получаю следующие ошибки:
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
Чего мне не хватает в Union здесь?
Обратите внимание, я попытался абстрагироватьбазовый класс и наличие Foo
и Bar
происходит от абстрактного базового класса class MyType(metaclass=abc.Meta)
, но появляется очень похожая ошибка.
Редактировать, чтобы добавить:
(py37) Juans-MBP: juan$ mypy --version
mypy 0.620