具有两个用例的类型提示功能
Posted
技术标签:
【中文标题】具有两个用例的类型提示功能【英文标题】:Type hinting function with two use cases 【发布时间】:2021-09-20 08:43:00 【问题描述】:我正在尝试完全键入提示一个函数,该函数确保一个元素在给定的字典中,然后检查元素类型是否是用户期望的。我的初始实现工作正常,如下所示
T = TypeVar("T")
def check_and_validate_element_in_dict(
element_name: str, dictionary: Dict[str, Any], element_type: Type[T]
) -> T:
assert element_name in dictionary
element = dictionary[element_name]
assert isinstance(element, element_type)
return element
它允许我替换它
assert "key1" in _dict
key1 = _dict["key1"]
assert isinstance(key1, type1)
assert "key2" in _dict
key2 = _dict["key2"]
assert isinstance(key2, type2)
有了这个
key1 = check_and_validate_element_in_dict("key1", _dict, type1)
key2 = check_and_validate_element_in_dict("key2", _dict, type2)
现在,这仅适用于要测试的元素类型只有一种,例如 int
、str
等。
我还希望能够在我的函数中测试多种不同的类型,比如
isinstance(element, (int, dict))
isinstance(element, (float, type(None)))
这里的问题是类型提示函数,以使其理解如果 element_type
是单个值 T
,则返回值是 T
,但如果 element_type 是例如其中之一T
和U
两种类型,返回值将是T
或U
。
我想这是可能的,但由于我还是类型提示领域的新手,我需要一些帮助!
编辑:
我尝试让函数支持单一类型或两种不同类型的元组作为基本情况,因此我将element_type
更新为
element_type: Union[Type[T], Tuple[Type[T], Type[T]]]
现在return element
语句被mypy
标记为错误:
Returning Any from function declared to return "T"
这也提出了一个问题:我是否需要将每个不同的输入类型指示为新的TypeVar
?在这种情况下,element_type
定义变为
# using U = TypeVar("U")
def ...(..., element_type: Union[Type[T], Tuple[Type[T], Type[U]]]) -> Union[T, U]:
在这种情况下,问题一直存在
Returning Any from function declared to return "T"
【问题讨论】:
首先要尝试的是element_type: Type[T] | Tuple[Type[T]]
- 当你这样做时会发生什么?
@kaya3 你对Type[T] | Tuple[Type[T]]
到底是什么意思?尤其是|
,还有Tuple[Type[T]]
表示一个元组里面只有一个类型
@HitLuca -- 在 Python 3.10 中添加了 |
运算符,以便为 typing.Union
启用更简单的注释。 Python 3.10 中的int | float
与早期版本中的Union[int, float]
相同。关于tuple
点,我同意——我认为这不是一个完美的解决方案。
对不起,我的意思是Tuple[Type[T], ...]
应该是一个任意多个元素的元组。
哦,我不知道|
操作,对不起,我使用的是python3.7。我其实也不知道你可以在 Tuple[Type[T], ...]
之类的东西中使用省略号!
【参考方案1】:
您可以使用typing.overload
,它允许您为一个函数注册多个不同的签名。用@overload
装饰的函数在运行时会被python 忽略,因此您可以通过在函数体中添加省略号...
将这些函数体留空。这些实现仅适用于类型检查器——您必须确保至少有一个没有用重载修饰的函数的“真实”实现。
from typing import TypeVar, overload, Any, Union, Dict, Type, Tuple
t0 = TypeVar('t0')
t1 = TypeVar('t1')
@overload
def check_and_validate_element_in_dict(
element_name: str,
dictionary: Dict[str, Any],
element_type: Type[t0]
) -> t0:
"""
Signature of the function if exactly one type
is supplied to argument element_type
"""
...
@overload
def check_and_validate_element_in_dict(
element_name: str,
dictionary: Dict[str, Any],
element_type: Tuple[Type[t0], Type[t1]]
) -> Union[t0, t1]:
"""
Signature of the function if a tuple of exactly two types
is supplied to argument element_type
"""
...
def check_and_validate_element_in_dict(
element_name: str,
dictionary: Dict[str, Any],
element_type: Any
) -> Any:
"""Concrete implementation of the function"""
assert element_name in dictionary
element = dictionary[element_name]
assert isinstance(element, element_type)
return element
然而,这感觉像是一个非常不完美的解决方案,因为它没有为传递给element_type
参数的任意长度的元组提供解决方案。仅当您知道元组的长度将是(例如)2、3 或 4 之一时,它才有效——然后您可以为每种情况提供重载实现。如果有人能想到更好的解决方案,肯定会感兴趣。
【讨论】:
我怀疑有这样的事情!几年前我读过它,但不知道如何寻找它,绝对是我在寻找的东西(你连续第二天帮助我看起来像,我想我需要雇用你作为个人类型提示导师!) 我同意这不是最好的方法,但我想我可以使用它,因为目前我最多有 3 种不同的类型检查要做 啊,太棒了——再一次,很高兴我能帮上忙!以上是关于具有两个用例的类型提示功能的主要内容,如果未能解决你的问题,请参考以下文章