[英]Type hint where one argument is the type of another
我无法为一对参数表达精确的类型提示,其中一个参数需要是某个类型的实例的值,另一个需要是类型本身或某个超类型。
在 Python 中看到这种情况的一种情况是在上下文管理器(类)的__exit__
方法中。
import typing as t
from types import TracebackType
from contextlib import AbstractContextManager
class Acme(AbstractContextManager):
def __exit__(self, exc_type: t.Type[Exception], exc: Exception,
tb: Tracebacktype) -> None:
...
这种特定情况可能无关紧要,因为上下文管理器由 Python 在内部处理,但我仍然想了解如何表达两个 arguments,其中第一个是第二个的(超)类型。
从概念上讲,我的问题是我想表达值exc_type
exc
某个子类型。 在上面的表达式中,我猜 mypy 会对 arguments 像LookupError, RuntimeError('foo')
非常满意,即使RuntimeError
不是LookupError
的类型。 有没有更好的方法来表达这一点,mypy 会发现这种错误?
更新
在这里使用 TypeVars 尝试一个测试用例:
import typing as t
C = t.TypeVar('C', bound=t.Collection)
def f(t: t.Type[C], c: C) -> None:
pass
f(t.Dict, [])
我希望 mypy 抱怨这段代码,因为即使空列表是一种集合,它也不是字典。
这种对Type[some_type_var]
的使用似乎不鼓励PEP中的一个部分,其中只提供了这种支持的一个子集(特别是用于将TypeVar
绑定到 class 类型)。 看来这种劝阻不是哲学上的(这将是 generics 在类型和值都是一流的语言中的常见用法) - 但与类型检查器的实际实现更相关。 将TypeVar
用于类方法签名(您问题的一个特例)甚至是对 pep 的后期添加。
不适用于 mypy 的可能解决方案(截至目前) :
TypeVar
Type[some_type_var]
的 function 签名中没有类型检查。 这不是基于some_type_var
是contravariant
还是covariant
的变量(也不应该是)。
TypeVar
的Type[TypeVar]
T = TypeVar("T")
Meta = TypeVar("Meta", bound=Type[T])
def foo(the_type: Meta, the_value: T):
....
T
和Meta
不能“绑定”在一起。
令我惊讶的是,在某些情况下,您可以排除一些这种行为(但这是一种特殊情况,这对我来说似乎未定义)
T = TypeVar('T', str, int, float, bytes)
class Foo:
def bar(self, the_type: Type[T], the_value: T):
print(isinstance(the_value, the_type))
f = Foo()
f.bar(str, "baz")
f.bar(str, b"baz") # wrong!
f.bar(int, 1)
f.bar(int, 3.15159) # wrong! (but no complaint)
f.bar(float, 1.0)
f.bar(float, 1) # wrong! (but no complaint)
f.bar(float, b'1.0') # wrong!
给予
so.py:nn: error: Value of type variable "T" of "bar" of "Foo" cannot be "object"
so.py:nn: error: Value of type variable "T" of "bar" of "Foo" cannot be "object"
Found 2 errors in 1 file (checked 1 source file)
但似乎只适用于 python 的原始类型(这不适用于用户空间类型)(同样,只有一些python 的原始类型如图所示(参见float
和int
的错误错过)。我认为这是一个明确的“不错-to-have” TypeVar
的扩展(并使更多Generic
用例成为可能)。
mypy上有一些相关的问题:
这就是TypeVar
的用途:你想要这样的东西:
from types import TracebackType
from typing import Type, TypeVar
from contextlib import AbstractContextManager
_E = TypeVar('_E', bound=Exception)
class Acme(AbstractContextManager):
def __exit__(
self,
exc_type: Type[_E],
exc: _E,
tb: Tracebacktype
) -> None:
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.