从类型中提取数据

Posted

技术标签:

【中文标题】从类型中提取数据【英文标题】:extracting data from typing types 【发布时间】:2018-12-12 18:58:59 【问题描述】:

我在使用 Python 中的 typing 类型时遇到了一些问题,不仅仅是类型提示:

>>> from typing import List
>>> string_list = ['nobody', 'expects', 'the', 'spanish', 'inqusition']
>>> string_list_class = List[str]

现在我想

    检查string_list 是否符合string_list_class。 检查string_list_class 是否为列表。 如果是,请检查类,string_list_class 是一个列表。

我发现自己无法实现其中任何一个:

>>> isinstance(string_list, string_list_class)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/typing.py", line 708, in __instancecheck__
    return self.__subclasscheck__(type(obj))
  File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/typing.py", line 716, in __subclasscheck__
    raise TypeError("Subscripted generics cannot be used with"
TypeError: Subscripted generics cannot be used with class and instance checks

>>> issubclass(string_list_class, List)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/typing.py", line 716, in __subclasscheck__
    raise TypeError("Subscripted generics cannot be used with"
TypeError: Subscripted generics cannot be used with class and instance checks

documentation 对此也没什么帮助。此外,API 似乎并不打算以这种方式使用,但是,我需要使用该功能

四处游荡

我发现回答 2. 的一种方法是,那个

>>> type(string_list_class)
<class 'typing._GenericAlias'>

虽然我无法访问_GenericAlias,但我可以自己构建它:

>>> _GenericAlias = type(List[str])
>>> isinstance(string_list_class, _GenericAlias)
True

但是,这似乎根本不是一个好的解决方案,它还会为其他类(如 Collection)生成 True

对于 1. 和 3. 我可以想象用 repr(type(string_list))repr(string_list_class) 一起破解某些东西,并以某种方式将该字符串与某物进行比较,但这也不是一个好的解决方案。

但必须有更好的方法来做到这一点

【问题讨论】:

我明白了第 1 点,但第 2 点的目的是什么?如果string_list 符合string_list_class,那么您已经知道它是一个列表。我不知道第 3 点是什么意思。 我想检查string_list_class 是否是一个一般的列表类型。它可能是strintMyObject 或其他内容的列表。这与 1 无关。对于 3,我想从 List[MyObject] 中提取 MyObject 好的,我明白了。但是...我不确定同时问 3 个几乎不相关的问题是否是个好主意... 我同意,但恕我直言,它们并非完全无关,对其中一两个问题的回答可以回答其他问题。我无法找到解决方案,但如果有,同一来源可能也可以回答其他问题。 关于第 3 点,请参阅How to access the type arguments of typing.Generic?。 What's the correct way to check if an object is a typing.Generic? 可能对第 2 点有所帮助。 【参考方案1】:

检查变量是否符合类型对象

要检查string_list 是否符合string_list_class,可以使用typeguard 类型检查库。

from typeguard import check_type

try:
    check_type('string_list', string_list, string_list_class)
    print("string_list conforms to string_list_class")
except TypeError:
    print("string_list does not conform to string_list_class")

检查类型对象的泛型

要检查string_list_class 是否为列表类型,您可以使用typing_inspect 库:

from typing_inspect import get_origin
from typing import List

get_origin(List[str]) # -> List

您也可以使用私有的__origin__ 字段,但不能保证它的稳定性。

List[str].__origin__ # -> list

检查类型对象的类型参数

要检查类,string_list_class 是一个列表,您可以再次使用 typing_inspect 库。

from typing_inspect import get_parameters
from typing import List

assert get_parameters(List[str])[0] == str

和以前一样,如果您愿意冒险,也可以使用一个私有字段

List[str].__args__[0] # -> str

【讨论】:

值得注意的是,typing_inspect 中的许多功能在 python 3.9 中不起作用。不幸的是,对泛型类型进行运行时检查似乎有点不可靠 见github.com/ilevkivskyi/typing_inspect/issues/65

以上是关于从类型中提取数据的主要内容,如果未能解决你的问题,请参考以下文章

从 Power Query 中的单元格值中提取数据类型?

如何从spark中的嵌套结构类型中提取列名和数据类型

如何从复杂的猪数据类型中提取简单的猪数据类型

如何从字节数组中提取长数据类型?

如何从 Glue Dynamic Dataframe 中提取列名和数据类型?

从 SQL Server 中的 XML 数据类型字段中提取数据