如何将参数传递给 Python 3 中的自定义静态类型提示?
How do I pass arguments to custom static type hints in Python 3?
我是 Python 3 中静态类型提示的超级粉丝和拥护者。我已经使用它们一段时间了,没有任何问题。
我只是 运行 进入了一个我似乎无法编译的新边缘案例。如果我想定义一个自定义类型,然后定义它的参数怎么办?
比如这个常见于Python 3:
from typing import List, NewType
CustomObject = NewType('CustomObject', List[int])
def f(data: List[CustomObject]):
# do something
但这不会编译:
class MyContainer():
# some class definition ...
from typing import NewType
SpecialContainer = NewType('SpecialContainer', MyContainer)
def f(data: SpecialContainer[str]):
# do something
我意识到 SpecialContainer
在这种情况下在技术上是一个函数,但它不应该在类型签名的上下文中被评估为一个函数。第二个代码片段因 TypeError: 'function' object is not subscriptable
.
而失败
编译我的代码示例
您必须从头开始设计 classes 以接受静态类型提示。这不满足我最初的用例,因为我试图声明第 3 方的特殊子类型 classes,但它编译了我的代码示例。
from typing import Generic, TypeVar, Sequence, List
# Declare your own accepted types for your container, required
T = TypeVar('T', int, str, float)
# The custom container has be designed to accept types hints
class MyContainer(Sequence[T]):
# some class definition ...
# Now, you can make a special container type
# Note that Sequence is a generic of List, and T is a generic of str, as defined above
SpecialContainer = TypeVar('SpecialContainer', MyContainer[List[str]])
# And this compiles
def f(data: SpecialContainer):
# do something
子类型化第 3 方 Class
我的初衷是创建一个类型提示来解释函数 f()
如何获取一个 pd.DataFrame
对象,该对象由整数索引并且其单元格都是字符串。使用上面的答案,我想出了一种人为的表达方式。
from typing import Mapping, TypeVar, NewType, NamedTuple
from pandas import pd
# Create custom types, required even if redundant
Index = TypeVar('Index')
Row = TypeVar('Row')
# Create a child class of pd.DataFrame that includes a type signature
# Note that Mapping is a generic for a key-value store
class pdDataFrame(pd.DataFrame, Mapping[Index, Row]):
pass
# Now, this compiles, and explains what my special pd.DataFrame does
pdStringDataFrame = NewType('pdDataFrame', pdDataFrame[int, NamedTuple[str]])
# And this compiles
def f(data: pdStringDataFrame):
pass
值得吗?
如果您正在编写类似于 Sequence
、Mapping
或 Any
等容器泛型的自定义 class,那就去做吧.可以自由地将类型变量添加到您的 class 定义中。
如果您尝试标注未实现类型提示的第三方 class 的特定用法:
- 尝试使用现有的类型变量来表达您的观点,例如
MyOrderedDictType = NewType('MyOrderedDictType', Dict[str, float])
- 如果这不起作用,您将不得不用琐碎的子 classes 和类型变量来打乱您的命名空间,以获得要编译的类型提示。最好使用文档字符串或注释来解释您的情况。
我是 Python 3 中静态类型提示的超级粉丝和拥护者。我已经使用它们一段时间了,没有任何问题。
我只是 运行 进入了一个我似乎无法编译的新边缘案例。如果我想定义一个自定义类型,然后定义它的参数怎么办?
比如这个常见于Python 3:
from typing import List, NewType
CustomObject = NewType('CustomObject', List[int])
def f(data: List[CustomObject]):
# do something
但这不会编译:
class MyContainer():
# some class definition ...
from typing import NewType
SpecialContainer = NewType('SpecialContainer', MyContainer)
def f(data: SpecialContainer[str]):
# do something
我意识到 SpecialContainer
在这种情况下在技术上是一个函数,但它不应该在类型签名的上下文中被评估为一个函数。第二个代码片段因 TypeError: 'function' object is not subscriptable
.
编译我的代码示例
您必须从头开始设计 classes 以接受静态类型提示。这不满足我最初的用例,因为我试图声明第 3 方的特殊子类型 classes,但它编译了我的代码示例。
from typing import Generic, TypeVar, Sequence, List
# Declare your own accepted types for your container, required
T = TypeVar('T', int, str, float)
# The custom container has be designed to accept types hints
class MyContainer(Sequence[T]):
# some class definition ...
# Now, you can make a special container type
# Note that Sequence is a generic of List, and T is a generic of str, as defined above
SpecialContainer = TypeVar('SpecialContainer', MyContainer[List[str]])
# And this compiles
def f(data: SpecialContainer):
# do something
子类型化第 3 方 Class
我的初衷是创建一个类型提示来解释函数 f()
如何获取一个 pd.DataFrame
对象,该对象由整数索引并且其单元格都是字符串。使用上面的答案,我想出了一种人为的表达方式。
from typing import Mapping, TypeVar, NewType, NamedTuple
from pandas import pd
# Create custom types, required even if redundant
Index = TypeVar('Index')
Row = TypeVar('Row')
# Create a child class of pd.DataFrame that includes a type signature
# Note that Mapping is a generic for a key-value store
class pdDataFrame(pd.DataFrame, Mapping[Index, Row]):
pass
# Now, this compiles, and explains what my special pd.DataFrame does
pdStringDataFrame = NewType('pdDataFrame', pdDataFrame[int, NamedTuple[str]])
# And this compiles
def f(data: pdStringDataFrame):
pass
值得吗?
如果您正在编写类似于
Sequence
、Mapping
或Any
等容器泛型的自定义 class,那就去做吧.可以自由地将类型变量添加到您的 class 定义中。如果您尝试标注未实现类型提示的第三方 class 的特定用法:
- 尝试使用现有的类型变量来表达您的观点,例如
MyOrderedDictType = NewType('MyOrderedDictType', Dict[str, float])
- 如果这不起作用,您将不得不用琐碎的子 classes 和类型变量来打乱您的命名空间,以获得要编译的类型提示。最好使用文档字符串或注释来解释您的情况。
- 尝试使用现有的类型变量来表达您的观点,例如