对于使用 `type()` 构造的类型,mypy“作为类型无效”
Posted
技术标签:
【中文标题】对于使用 `type()` 构造的类型,mypy“作为类型无效”【英文标题】:mypy "is not valid as a type" for types constructed with `type()` 【发布时间】:2020-02-23 22:34:46 【问题描述】:mypy 抱怨error: Variable "packagename.Foo" is not valid as a type
Foo = type('Foo', (), )
Bar = Optional[Foo]
可以通过将类型定义为类来修复此错误:
class Foo:
pass
Bar = Optional[Foo]
还有其他方法可以解决这个问题吗?我需要保持类型定义动态。
【问题讨论】:
为什么要这样使用type()
?请注意,mypy
不会运行/评估代码,所以我认为不会执行 type
来“创建新类型对象”
我猜这是因为 mypy can't handle dynamic base classes.
一般来说,静态类型检查器无法处理动态创建的类型。
我不太明白的是,如果你“承诺”类型检查器你的变量将是类类型a: Type[Foo] = Foo
,为什么它不认为是有效的class Bar(a)
?我们可以在 TypeScript 中毫无问题地做到这一点:typescriptlang.org/play/#code/…
我打算建议不同之处在于class
,作为一个句法结构,必须产生一个类型,而type
可以反弹到任何可调用的运行。但是,也可以通过指定不同的元类来修改 class
语句。最后,请记住,mypy
确实是一个 hack(从最好的意义上说)试图从 Python 所基于的固有动态数据模型中挤出尽可能多的静态类型。它必须解决许多极端情况。
【参考方案1】:
作为一种解决方法,这个怎么样?
from typing import Optional, TYPE_CHECKING
if TYPE_CHECKING:
class Foo: pass
else:
Foo = type('Foo', (), )
Bar = Optional[Foo]
typing.TYPE_CHECKING
是一个常量,在编译时始终为True
,在运行时始终为False
。通过这种方式,我们可以只告诉 MyPy 静态定义,但在运行时我们可以随心所欲地动态。
不过,您应该知道,这在很大程度上是一种解决方法,而不是解决方案。通过这种方式,我们实质上是在向类型检查器撒谎Foo
的真实定义。这意味着 MyPy 可能无法发现某些地方的错误,并且可能会引发其他地方不存在的错误。在某些情况下,在运行时动态构造类型非常有用,但它违反了 Python 中类型检查的一些基本原则,因此如果没有某种 hack,你将很难让类型检查器批准你正在做的事情。
【讨论】:
在我的用例中,我有一个返回类 (var=class_factory()
) 的类工厂函数。这是我能找到的唯一方法让 mypy 接受 var
作为一个类。谢谢!【参考方案2】:
这对你有用吗?
from typing import TypeVar, Optional
Foo = TypeVar('Foo')
Bar = Optional[Foo]
【讨论】:
这与问题中已经提出的class Bar:
方法有何根本不同?使这项工作起作用的部分是它使用了class
语句——在顶部添加dataclass
不会影响这一点。
所以这里要创建动态类型,如果你用class关键字定义类型有什么不容易的?
恐怕您的编辑仍然无法解决 OP 的原始问题:/ TypeVar
not 是否以与调用 type
相同的方式创建一个新类用三个参数就可以了。 TypeVar
文档。 type
文档。以上是关于对于使用 `type()` 构造的类型,mypy“作为类型无效”的主要内容,如果未能解决你的问题,请参考以下文章