Python:如何检查定义的types. uniontype中有哪些类型?



我正在使用Python 3.11,我需要检测一个可选的属性是否为Enum类型(即Enum子类的类型)。

typing.get_type_hints()我可以得到类型提示作为字典,但如何检查如果字段的类型是可选的Enum(子类)?如果我能得到任何可选字段的类型就更好了,不管它是Optional[str],Optional[int],Optional[Class_X]等。

示例代码

from typing import Optional, get_type_hints
from enum import IntEnum, Enum
class TestEnum(IntEnum):
foo = 1
bar = 2

class Foo():
opt_enum : TestEnum | None = None
types = get_type_hints(Foo)['opt_enum']
这是

(ipython)

In [4]: Optional[TestEnum] == types
Out[4]: True

这些都失败了

(是的,这是绝望的尝试)

In [6]: Optional[IntEnum] == types
Out[6]: False

In [11]: issubclass(Enum, types)
Out[11]: False

In [12]: issubclass(types, Enum)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [12], line 1
----> 1 issubclass(types, Enum)
TypeError: issubclass() arg 1 must be a class

In [13]: issubclass(types, Optional[Enum])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [13], line 1
----> 1 issubclass(types, Optional[Enum])
File /usr/lib/python3.10/typing.py:1264, in _UnionGenericAlias.__subclasscheck__(self, cls)
1262 def __subclasscheck__(self, cls):
1263     for arg in self.__args__:
-> 1264         if issubclass(cls, arg):
1265             return True
TypeError: issubclass() arg 1 must be a class

In [7]: IntEnum in types
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [7], line 1
----> 1 IntEnum in types
TypeError: argument of type 'types.UnionType' is not iterable

为什么我需要这个

我有几个情况下,我从csv文件导入数据,并从每行创建一个类的对象。csv.DictReader()返回dict[str, str],我需要在尝试创建对象之前修复字段的类型。然而,一些对象字段是Optional[int],Optional[bool],Optional[EnumX]Optional[ClassX]。我有几个这样的类多继承我的CSVImportable()类/接口。我想在CSVImportable()类中实现逻辑,而不是在每个子类中以字段感知的方式编写大致相同的代码。这个CSVImportable._field_type_updater()应该:

  1. 至少正确更改基本类型和枚举的类型
  2. 优雅地跳过Optional[ClassX]字段

当然我也很感谢更好的设计:-)

当你处理一个参数化的类型(通用的或特殊的如typing.Optional),你可以通过get_args/get_origin检查它。

这样做,您将看到T | S的实现与typing.Union[T, S]略有不同。前者为types.UnionType,后者为typing.Union。不幸的是,这意味着要覆盖这两个变量,我们需要两个不同的检查。

from types import UnionType
from typing import Union, get_origin
def is_union(t: object) -> bool:
origin = get_origin(t)
return origin is Union or origin is UnionType

使用typing.Optional只是在引擎盖下使用typing.Union,所以原点是相同的。下面是一个工作演示:

from enum import IntEnum
from types import UnionType
from typing import Optional, get_type_hints, get_args, get_origin, Union

class TestEnum(IntEnum):
foo = 1
bar = 2

class Foo:
opt_enum1: TestEnum | None = None
opt_enum2: Optional[TestEnum] = None
opt_enum3: TestEnum
opt4: str

def is_union(t: object) -> bool:
origin = get_origin(t)
return origin is Union or origin is UnionType

if __name__ == "__main__":
for name, type_ in get_type_hints(Foo).items():
if type_ is TestEnum or is_union(type_) and TestEnum in get_args(type_):
print(name, "accepts TestEnum")

输出:

opt_enum1接受TestEnumopt_enum2接受TestEnumopt_enum3接受TestEnum

相关内容

  • 没有找到相关文章

最新更新