Mypy返回了一个我不理解的错误(也无法以简化形式重新创建)。谷歌搜索错误证明是困难的(给了问号)。
有人知道这个错误是什么意思吗?问号具体表示什么?
typeBasePage = TypeVar("typeBasePage", bound="BasePage") # any instance subclass of BasePage
typeNavCls = Type[typeBasePage] # error occurs here - trying to make an alias
class Nav:
def __init__(self, cls: typeNavCls):
self.cls: typeNavCls = cls
class BasePage(Base):
...
# redacted because it's huge
相关代码:
typeB = TypeVar('typeB', bound='B')
tAlias = Type[typeB]
class Nav:
def __init__(self, cls: tAlias):
self.cls: tAlias = cls
class A: pass
class B(A): pass
再次,如果我尝试以非常简化的形式重新创建上述代码,mypy不会出错。
microdnf
答案 0 :(得分:1)
如果没有完整的复制程序,恐怕很难确定问题所在。我认为这很可能是mypy错误:mypy可能会由于代码中的某些循环而感到困惑。也许是导入周期,有些怪异,涉及模块和子模块的导入,您的mypy缓存以某种方式损坏了...
另一种可能性是您的代码以某种方式不能以安全的方式键入,并且此错误只是mypy试图继续奋斗的下游结果。
为帮助缩小问题范围,建议您在确保使用最新版本并删除.mypy_cache
文件后重新运行mypy。如果问题仍然存在,则值得尝试稳定地删除代码库中无关的部分,以尝试找出一个再现对象。
也就是说,在这里完全不使用类型别名也可能是值得的:在您的示例中,使用别名/类型var实际上没有任何好处。
简而言之,如果您在类型别名中使用任何类型变量,则这些typevar实际上总是 free :在开始使用别名时,需要将它们明确绑定到某种类型。因此,您不想做def __init__(self, cls: typeNavCls)
,而是想做def __init__(self, cls: typeNavCls[SomeTypeHere])
。
否则,mypy会将您的签名视为与def __init__(self, cls: typeNavCls[Any])
完全相同,就像将def foo(x: List)
的签名视为def foo(x: List[Any])
一样。
您可以将mypy配置为通过使用--strict
标记或--disallow-any-generics
标志运行它来警告您有关此问题的信息:前者自动启用后者。
相反,您可能应该执行以下操作之一:
# Approach 1: If you don't want Nav to be inherently generic
class Nav:
def __init__(self, cls: Type[BasePage]):
self.cls = cls
# Approach 2: If you want Nav to be inherently generic
_TBasePage = TypeVar('_TBasePage', bound='BasePage')
class Nav(Generic[_TBasePage]):
def __init__(self, cls: Type[_TBasePage]):
self.cls = cls
# Approach 3: If you want to ensure two or more types are the same,
# but nothing else
class Nav:
def __init__(self, cls: Type[_TBasePage], instance: _TBasePage):
# ...but you won't be able to save 'cls' as a field here: your
# Nav class needs to be generic with respect to _TBasePage if you
# want to "preserve" whatever type that's bound to as a field.
# Approach 4: If your alias is complex enough where you want to
# force a relationship between two or more types within the alias
MyAlias = Tuple[Type[_TBasePage], _TBasePage]
class Nav:
def __init__(self, info: MyAlias[BasePageSubtype]):
self.info = info
# Approach 5: ...or if you want Nav to also be generic:
MyAlias = Tuple[Type[_TBasePage], _TBasePage]
class Nav(Generic[_TBasePage]):
def __init__(self, info: MyAlias[_TBasePage]):
self.info = info
# Important note: the previous example is actually exactly
# equivalent to doing:
_T1 = TypeVar('_T1', bound=BasePage)
MyAlias = Tuple[Type[_T1], T1]
_T2 = TypeVar('_T2', bound=BasePage)
class Nav(Generic[_T2]):
def __init__(self, info: MyAlias[_T2]):
self.info = info
方法1、2和3应该避开您原来遇到的问题。如果这些方法与您实际想要的方法相似,那么根本不使用别名就更简单/简洁了。而且,如果您不使用别名,那么您就不会遇到该错误。
但是,如果您的实际代码更像方法4或5,那么很可能需要进行更深入的研究。
关于您的self-answer here的最后一条注释:文档的这一部分是指在文字类型的上下文中使用问号 just 。但是您没有使用文字类型,因此此处的文档部分与此无关。
如果在常规实例之后出现问题,则表示该类型实际上是“未绑定类型”。这是mypy的一种特殊的仅供内部使用的类型,它用作应为类型但找不到对应定义的事物的占位符。
这意味着mypy中存在一个错误,导致Unbound类型出现在不应出现的位置,或者意味着存在其他可能合法的错误污染了下游错误。
答案 1 :(得分:0)
我相信我发现了问号是什么,但距离弄清楚为什么在mypy中发生错误的原因还很遥远。
https://mypy.readthedocs.io/en/latest/literal_types.html
如果您未在
Final
中提供显式类型,则c
的类型 变得对上下文敏感:mypy基本上会尝试“替换” 在执行键入之前使用的原始分配值 检查。这就是为什么显示的c
是Literal[19]?
的原因: 最后的问号反映了这种上下文相关的性质。