Python - 打字 - 可订阅类型的并集
Python - typing - union of subscriptable type
我想创建一个 Array
类型,它应该是 可订阅的 并且是 typing.List
和 numpy.ndarray
类型的联合。
我知道 numpy
没有存根,但是 those numpy stubs(作者 Machinalis)应该可以正常工作,因为它们是可订阅的。
这是预期的行为:
def foo(bar: Array[int])->None:
pass
foo([1,2,3]) # No typing error
foo(numpy.arange(4)) # No typing error
foo((1,2,3)) # Error: Expected Array[int], got Tuple[int]
foo([1.,2.,3.]) # Error: Expected Array[int], got Array[float]
我已经尝试了一些方法,但 none 都按预期工作。
在 Python 3.7 中你会怎么做?
我也会接受某种鸭子类型的解决方案,即使它不满足元组错误。重点是创建可订阅类型的可订阅联合。
谢谢。
我最好的尝试:(评论中的 mypy 错误)
class _meta_getitem(type):
def __getitem__(cls, x):
return cls.__getitem__(cls, x)
class Array(metaclass=_meta_getitem):
def __getitem__(self, element_type: type) -> type:
array_type = typing.Union[List[element_type], # error: Invalid type "element_type"
numpy.ndarray[element_type]]
return typing.NewType("Array[{}]".format(element_type.__name__),
array_type) # The type alias to Union is invalid in runtime context
if __name__ == "__name__":
x: Array[int] = numpy.arange(4) # "Array" expects no type arguments, but 1 given
创建 Union[List[T], Array[T]]
的类型别名应该可行:
from typing import TypeVar, Union, List
T = TypeVar('T')
Array = Union[List[T], numpy.ndarray[T]]
def foo(bar: Array[int]) -> None: pass
有关此技术的更多信息,请参阅 generic type aliases 上的 mypy 文档。
此代码可能会在运行时失败,因为 numpy.ndarray
实际上在运行时不可订阅,仅在类型提示世界中。您可以通过将自定义类型提示隐藏在 typing.TYPE_CHECKING
守卫后面来解决这个问题,它在运行时始终为 false,在类型检查时始终为 true。
你可以在 Python 3.7+:
中相对干净地做到这一点
from __future__ import annotations
from typing import TypeVar, Union, List, TYPE_CHECKING
if TYPE_CHECKING:
T = TypeVar('T')
Array = Union[List[T], numpy.ndarray[T]]
def foo(bar: Array[int]) -> None: pass
对于旧版本的 Python3,您必须将 Array[int]
包裹在一个字符串中,但是:
from typing import TypeVar, Union, List, TYPE_CHECKING
if TYPE_CHECKING:
T = TypeVar('T')
Array = Union[List[T], numpy.ndarray[T]]
def foo(bar: "Array[int]") -> None: pass
请注意,尝试通过在运行时将多个其他类型提示组合在一起来构建您自己的 Array
类型提示不太可能奏效:像 mypy 这样的静态分析工具通过实际分析您的代码而无需 运行它:它实际上不会尝试评估您的自定义 Array
class.
中的任何内容
一般来说,尝试在运行时 "use" 类型提示往往充满危险:它们实际上只是用作类型提示。
最后,您似乎误解了 NewType
的用途。我推荐阅读 the relevant docs for more info.
我想创建一个 Array
类型,它应该是 可订阅的 并且是 typing.List
和 numpy.ndarray
类型的联合。
我知道 numpy
没有存根,但是 those numpy stubs(作者 Machinalis)应该可以正常工作,因为它们是可订阅的。
这是预期的行为:
def foo(bar: Array[int])->None:
pass
foo([1,2,3]) # No typing error
foo(numpy.arange(4)) # No typing error
foo((1,2,3)) # Error: Expected Array[int], got Tuple[int]
foo([1.,2.,3.]) # Error: Expected Array[int], got Array[float]
我已经尝试了一些方法,但 none 都按预期工作。
在 Python 3.7 中你会怎么做?
我也会接受某种鸭子类型的解决方案,即使它不满足元组错误。重点是创建可订阅类型的可订阅联合。
谢谢。
我最好的尝试:(评论中的 mypy 错误)
class _meta_getitem(type):
def __getitem__(cls, x):
return cls.__getitem__(cls, x)
class Array(metaclass=_meta_getitem):
def __getitem__(self, element_type: type) -> type:
array_type = typing.Union[List[element_type], # error: Invalid type "element_type"
numpy.ndarray[element_type]]
return typing.NewType("Array[{}]".format(element_type.__name__),
array_type) # The type alias to Union is invalid in runtime context
if __name__ == "__name__":
x: Array[int] = numpy.arange(4) # "Array" expects no type arguments, but 1 given
创建 Union[List[T], Array[T]]
的类型别名应该可行:
from typing import TypeVar, Union, List
T = TypeVar('T')
Array = Union[List[T], numpy.ndarray[T]]
def foo(bar: Array[int]) -> None: pass
有关此技术的更多信息,请参阅 generic type aliases 上的 mypy 文档。
此代码可能会在运行时失败,因为 numpy.ndarray
实际上在运行时不可订阅,仅在类型提示世界中。您可以通过将自定义类型提示隐藏在 typing.TYPE_CHECKING
守卫后面来解决这个问题,它在运行时始终为 false,在类型检查时始终为 true。
你可以在 Python 3.7+:
中相对干净地做到这一点from __future__ import annotations
from typing import TypeVar, Union, List, TYPE_CHECKING
if TYPE_CHECKING:
T = TypeVar('T')
Array = Union[List[T], numpy.ndarray[T]]
def foo(bar: Array[int]) -> None: pass
对于旧版本的 Python3,您必须将 Array[int]
包裹在一个字符串中,但是:
from typing import TypeVar, Union, List, TYPE_CHECKING
if TYPE_CHECKING:
T = TypeVar('T')
Array = Union[List[T], numpy.ndarray[T]]
def foo(bar: "Array[int]") -> None: pass
请注意,尝试通过在运行时将多个其他类型提示组合在一起来构建您自己的 Array
类型提示不太可能奏效:像 mypy 这样的静态分析工具通过实际分析您的代码而无需 运行它:它实际上不会尝试评估您的自定义 Array
class.
一般来说,尝试在运行时 "use" 类型提示往往充满危险:它们实际上只是用作类型提示。
最后,您似乎误解了 NewType
的用途。我推荐阅读 the relevant docs for more info.